home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume89 / librarys / minrex04.1 < prev    next >
Text File  |  1989-05-11  |  77KB  |  2,016 lines

  1. Path: xanth!ames!sun-barr!sun!swap!page
  2. From: page%swap@Sun.COM (Bob Page)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v89i126:  minrexx - add a rexx port to your programs v0.4
  5. Message-ID: <104262@sun.Eng.Sun.COM>
  6. Date: 11 May 89 07:28:59 GMT
  7. Sender: news@sun.Eng.Sun.COM
  8. Lines: 2005
  9. Approved: page@sun.com
  10.  
  11. Submitted-by: kim@uts.amdahl.com (Kim E. DeVaughn)
  12. Posting-number: Volume 89, Issue 126
  13. Archive-name: libraries/minrexx04.1
  14.  
  15. This is the latest version of Tom Rokicki's code to show people how to
  16. add a 7-function ARexx port to their own code.
  17.  
  18. [uuencoded executable included.  ..bob]
  19.  
  20. # This is a shell archive.
  21. # Remove anything above and including the cut line.
  22. # Then run the rest of the file through 'sh'.
  23. # Unpacked files will be owned by you and have default permissions.
  24. #----cut here-----cut here-----cut here-----cut here----#
  25. #!/bin/sh
  26. # shar: SHell ARchive
  27. # Run the following text through 'sh' to create:
  28. #    README
  29. #    freedraw.c
  30. #    minrexx.c
  31. #    minrexx.h
  32. #    Makefile
  33. #    freeedraw.uu
  34. #    aspline.fd
  35. #    bspline.fd
  36. #    sample.fd
  37. #    saspline.fd
  38. #    sbspline.fd
  39. #    version.fd
  40. # This is archive 1 of a 1-part kit.
  41. # This archive created: Thu May 11 00:22:53 1989
  42. echo "extracting README"
  43. sed 's/^X//' << \SHAR_EOF > README
  44. XHere's "minrexx", a simple ARexx interface which can be easily patched into
  45. Xalmost any program, and an example from Fish Disk 1, where I add an ARexx
  46. Xport to freedraw.
  47. X
  48. XFor documentation on Minrexx, refer to the .c and .h file.
  49. X
  50. XFor documentation on the Freedraw port, see the portions of freedraw.c
  51. Xdelimited by "#ifdef TALKTOREXX".
  52. X
  53. XEnjoy!
  54. SHAR_EOF
  55. echo "extracting freedraw.c"
  56. sed 's/^X//' << \SHAR_EOF > freedraw.c
  57. X#ifdef TALKTOREXX
  58. X/*
  59. X *   This program is an example of how to add a Rexx port to a given
  60. X *   program.  I thought it particularly appropriate to grab a program
  61. X *   off Fred Fish Disk 1.  All the REXX stuff is bracketed by `ifdef
  62. X *   TALKTOREXX', so you can identify it easily.  If you compile with
  63. X *   TALKTOREXX unset, you will get the default program with no REXX
  64. X *   port.
  65. X *
  66. X *   The REXX port on this program adds another 3K to the executable
  67. X *   size, but a lot of functionality comes with that.  You can draw
  68. X *   from Rexx, spawn macros from Rexx, etc.  But go to the next
  69. X *   TALKTOREXX for more information.
  70. X *
  71. X *   To run a rexx macro on startup, simply give that rexx macro as
  72. X *   part of the command line, as in
  73. X *
  74. X *      freedraw sample
  75. X *
  76. X *   or
  77. X *
  78. X *      freedraw bspline 20 100 20 20 280 20 280 100
  79. X *
  80. X *   All modifications are by Radical Eye Software, and all modifications
  81. X *   are placed in the public domain.
  82. X */
  83. X#endif
  84. X/************************************************************************/
  85. X/***                FreeDraw - PD graphics for Amiga                  ***/
  86. X/***                                                                  ***/
  87. X/***      This is an extremely simple graphics editor which works in  ***/
  88. X/***   the windowing environment of the Amiga.  It is very limited    ***/
  89. X/***   in features, but I hope to add a lot more, and I would be      ***/
  90. X/***   happy to receive assistance from anyone who wants to give it.  ***/
  91. X/***      The basic idea of this program is to provide some minimal   ***/
  92. X/***   image editing functions which can be used to develop images    ***/
  93. X/***   for other programs.  I know there will be a lot of Paint type  ***/
  94. X/***   type programs avaialable soon, but what are we supposed to use ***/
  95. X/***   now?  The most important features to add now will probably be  ***/
  96. X/***   those related to "cut and paste", disk srtorage and retrieval, ***/
  97. X/***   and "single-pixel" editing like Mac's "fatbits".               ***/
  98. X/***      I intend to use the IFF standard for the image storage and  ***/
  99. X/***   retrieval and will be coding a "Files" menu soon.  The work    ***/
  100. X/***   required for "cut and paste" should be almost trivial, but I   ***/
  101. X/***   still may not get to it for a while.  Fatbits editing from one ***/
  102. X/***   window to another involves some manipulations of the RastPorts ***/
  103. X/***   which still elude me, as I have only recently begun to use the ***/
  104. X/***   Amiga and don't yet understand some important details of these ***/
  105. X/***   structures.  This would be a great item for one of the genius  ***/
  106. X/***   members of the Amiga programming community to provide.         ***/
  107. X/***      There are only two menu topics in this version, so using it ***/
  108. X/***   is really quite easy.  Boxes are not allowed to be drawn in    ***/
  109. X/***   areas outside of the window where border gadgets are located,  ***/
  110. X/***   and the pen-draw mode also clips to these same boundaries.  If ***/
  111. X/***   you have begun to draw a box by clicking the left button while ***/
  112. X/***   the cursor is located in the FreeDraw window, then you can     ***/
  113. X/***   cancel that box by clicking the right button.  In the pen mode ***/
  114. X/***   pressing and holding the left button will draw.   Colors are   ***/
  115. X/***   selected by simply releasing the menu button over the desired  ***/
  116. X/***   color in the Color menu.   The erase feature always clears the ***/
  117. X/***   window to the currently selected color.                        ***/
  118. X/***      This is no gem of programming style, but you're getting it  ***/
  119. X/***   for the right price so be patient with its design flaws.  New  ***/
  120. X/***   versions will appear here on BIX as soon as I can get them in  ***/
  121. X/***   shape for release.  I apologize to anyone who objects to my    ***/
  122. X/***   lack of coding grace, but I just want to get the project off   ***/
  123. X/***   the ground, and improvements will be forthcoming.  There are   ***/
  124. X/***   a lot of comments, but I didn't know what needed to be made    ***/
  125. X/***   clear so I just commented everything.                          ***/
  126. X/***                                                                  ***/
  127. X/***      If you like the idea of a PD graphics program and would be  ***/
  128. X/***   interested in doing some development work, then please write   ***/
  129. X/***   me at the address listed below, or call if you prefer.  I do   ***/
  130. X/***   want to know if there is any interest in such a project, so    ***/
  131. X/***   I will be glad to discuss any ideas you might have.  Also, as  ***/
  132. X/***   I do not currently use CompuServe or any other major nets, I   ***/
  133. X/***   would appreciate if someone would post this listing there.     ***/
  134. X/***      I hope somebody enjoys this.  Have Fun.                     ***/
  135. X/***                                           Rick Ross 11/14/85     ***/
  136. X/***                                                                  ***/
  137. X/***        My address:                                               ***/
  138. X/***                    Richard M. Ross, Jr.                          ***/
  139. X/***                    Eidetic Imaging                               ***/
  140. X/***                    740 N. 22nd Street                            ***/
  141. X/***                    Philadelphia, PA  19130                       ***/
  142. X/***                                                                  ***/
  143. X/***                    Phone - (215) 236-7388                        ***/
  144. X/************************************************************************/
  145. Xchar *VERSION = "Freedraw 0.01 by Richard M. Ross" ;
  146. X/*  compiler directives to fetch the necessary header files */
  147. X
  148. X#include <exec/types.h>
  149. X#include <exec/exec.h>
  150. X#include <intuition/intuition.h>
  151. X#include <intuition/intuitionbase.h>
  152. X#include <graphics/gfx.h>
  153. X#include <graphics/regions.h>
  154. X#include <graphics/copper.h>
  155. X#include <graphics/gels.h>
  156. X#include <graphics/gfxbase.h>
  157. X#include <devices/keymap.h>
  158. X#include <hardware/blit.h>
  159. X
  160. X/*   These definitions are used by intuition for
  161. X *   calls to OpenLibrary() in order to ensure
  162. X *   that an appropriate ROM revision is
  163. X *   available.
  164. X */
  165. X
  166. X#define INTUITION_REV 1L
  167. X#define GRAPHICS_REV  1L
  168. X
  169. X/*   Intuition always wants to see these declarations */
  170. Xstruct IntuitionBase *IntuitionBase;
  171. Xstruct GfxBase *GfxBase;
  172. X
  173. X/*   This is the Window structure declaration.
  174. X *   Nothing fancy is going on here, but note
  175. X *   the Flags and IDCMPFlags members of the
  176. X *   structure define which messages will be
  177. X *   sent by Intuition.  I haven't used them all
  178. X *   and if you want to change the settings you
  179. X *   should probably do it her instead of using
  180. X *   ModifyIDCMP later.
  181. X */
  182. X
  183. Xstruct NewWindow NewWindow = {
  184. X   10,
  185. X   10,
  186. X   600,
  187. X   180,
  188. X   0,
  189. X   1,
  190. X   CLOSEWINDOW | MOUSEMOVE | MOUSEBUTTONS | MENUPICK
  191. X   | NEWSIZE | INACTIVEWINDOW,
  192. X   WINDOWCLOSE | SMART_REFRESH | ACTIVATE | WINDOWDRAG
  193. X   | WINDOWDEPTH | WINDOWSIZING | REPORTMOUSE,
  194. X   NULL,
  195. X   NULL,
  196. X   (UBYTE *)"AMIGA FreeDraw 0.01",
  197. X   NULL,
  198. X   NULL,
  199. X   100, 35,
  200. X   -1, -1,
  201. X   WBENCHSCREEN,
  202. X};
  203. X#ifdef TALKTOREXX
  204. X/*
  205. X *   We need our include file.
  206. X */
  207. X#include "minrexx.h"
  208. X/*
  209. X *   These are the REXX functions defined at the bottom of the file.
  210. X */
  211. Xvoid rexxcolor(), rexxbox(), rexxfbox(), rexxline(), rexxtofront(),
  212. X    rexxtoback(), rexxexit(), rexxversion(), rexxspawn() ;
  213. Xint disp() ;
  214. X/*
  215. X *   Here is our command association list.  Note that in this case,
  216. X *   we are setting the userdata field to be a function to call.
  217. X *   Dispatch will still take place through disp(), so common head
  218. X *   and tail stuff can go there.
  219. X *
  220. X *   Commands are all lower case, so we match either upper or lower.
  221. X *   (This is a requirement of minrexx.)
  222. X */
  223. Xstruct rexxCommandList rcl[] = {
  224. X   { "color", (APTR)&rexxcolor },
  225. X   { "box", (APTR)&rexxbox },
  226. X   { "fbox", (APTR)&rexxfbox },
  227. X   { "line", (APTR)&rexxline },
  228. X   { "tofront", (APTR)&rexxtofront },
  229. X   { "toback", (APTR)&rexxtoback },
  230. X   { "exit", (APTR)&rexxexit },
  231. X   { "version", (APTR)&rexxversion },
  232. X   { "spawn", (APTR)&rexxspawn },
  233. X   { NULL, NULL } } ;
  234. X#endif
  235. X/*******************************************************************/
  236. X/*      DrawBox - Simple routine to draw an unfilled rectangle     */
  237. X/*   It accepts the  coordinates of the top-left and lower-right   */
  238. X/*   points of the rectangle, a pointer to the Window structure,   */
  239. X/*   and the color in which to render the rectangle.  The current  */
  240. X/*   FgPen color of the window is preserved thru the call.  No     */
  241. X/*   clipping is done.                                             */
  242. X/*******************************************************************/
  243. Xvoid DrawBox( tlx, tly, brx, bry, window, color )
  244. XSHORT tlx, tly;                  /* top-left x,y coordinates */
  245. XSHORT brx, bry;                  /* lower-right x,y coordinates */
  246. Xstruct Window *window;           /* pointer to target window */
  247. XBYTE color;                      /* color to use for render */
  248. X   {
  249. X   BYTE OldColor = window->RPort->FgPen;   /* save window's FgPen */
  250. X
  251. X   SetAPen( window->RPort, (long)color );        /* set draw color for box  */
  252. X   Move(window->RPort, (long)tlx, (long)tly);          /* move to top-left point  */
  253. X   Draw(window->RPort, (long)brx, (long)tly);          /* and draw to each of the */
  254. X   Draw(window->RPort, (long)brx, (long)bry);          /* four corners of the box */
  255. X   Draw(window->RPort, (long)tlx, (long)bry);
  256. X   Draw(window->RPort, (long)tlx, (long)tly);
  257. X   SetAPen( window->RPort, (long)OldColor );     /* restore old FgPen */
  258. X   }
  259. X
  260. X
  261. X/*********************************************************/
  262. X/*                 Color Select Menu                     */
  263. X/*                                                       */
  264. X/*      This is where the menu for color selection is    */
  265. X/*   defined.  It should be flexible enough to allow for */
  266. X/*   increased palette sizes, but this version is only   */
  267. X/*   for the 4-color mode of the WorkBench screen.       */
  268. X/*********************************************************/
  269. X
  270. X/*   A few definitions are needed here.
  271. X *   Note that MAXPAL should be increased
  272. X *   to allow for palette larger than
  273. X *   four colors.    
  274. X */
  275. X#define ITEMSTUFF (ITEMENABLED | HIGHBOX)
  276. X#define CW 40
  277. X#define CH 25
  278. X#define MAXPAL 4
  279. X
  280. X/*   declare enough storage for required
  281. X *   number of menu items and associated
  282. X *   images.  This menu will be using
  283. X *   graphics renditions of menu items,
  284. X *   so the Image structures must be
  285. X *   declared.  This menu is modeled after
  286. X *   the one found in the IconEd source.
  287. X */
  288. Xstruct MenuItem coloritem[MAXPAL];
  289. Xstruct Image colorimage[MAXPAL];
  290. X
  291. X/*   array of palette sizes to correspond with
  292. X *   depth of window in bit-planes
  293. X */
  294. XSHORT palette[] = { 2, 4, 8, 16, 32 };
  295. X
  296. X
  297. X/*****************************************************************/
  298. X/*    The following function initializes the structure arrays    */
  299. X/*   needed to provide the Color menu topic.                     */
  300. X/*****************************************************************/
  301. XInitColorItems( depth )
  302. XSHORT depth;               /* number of bit-planes in window */
  303. X   {
  304. X   SHORT n, colors;
  305. X
  306. X   colors = palette[depth-1];
  307. X   for( n=0; n<colors; n++ )           /* loop for max number of items */
  308. X      {
  309. X      coloritem[n].NextItem = &coloritem[n+1];
  310. X      coloritem[n].ItemFill = (APTR)&colorimage[n];
  311. X      /*   the next two items might be changed for
  312. X       *   when bit-planes is greater than 2
  313. X       */
  314. X      coloritem[n].LeftEdge = 2 + CW * (n % 4);
  315. X      coloritem[n].TopEdge = CH * (n / 4);
  316. X      coloritem[n].Width = CW;
  317. X      coloritem[n].Height = CH;
  318. X      coloritem[n].Flags = ITEMSTUFF;
  319. X      coloritem[n].MutualExclude = 0;
  320. X      coloritem[n].SelectFill = NULL;
  321. X      coloritem[n].Command = 0;
  322. X      coloritem[n].SubItem = NULL;
  323. X      coloritem[n].NextSelect = 0;
  324. X
  325. X      colorimage[n].LeftEdge = 1;
  326. X      colorimage[n].TopEdge = 1;
  327. X      colorimage[n].Width = CW-2;
  328. X      colorimage[n].Height = CH-2;
  329. X      colorimage[n].Depth = depth;
  330. X      colorimage[n].ImageData = NULL;
  331. X      colorimage[n].PlanePick = 0;
  332. X      colorimage[n].PlaneOnOff = n;
  333. X      }
  334. X   coloritem[colors-1].NextItem = NULL;   /* needed for last item in list */
  335. X   return( 0 );
  336. X   }
  337. X
  338. X
  339. X/*****************************************************/
  340. X/*                Draw Mode Menu                     */
  341. X/*                                                   */
  342. X/*      Here are the code and data declarations for  */
  343. X/*   the DrawMode menu.  Current choices are limited */
  344. X/*   to Erase, Filled Box, Hollow Box, and PenDraw.  */
  345. X/*****************************************************/
  346. X
  347. X/* define maximum number of menu items */
  348. X#define DMODEMAX 4
  349. X
  350. X/*   declare storage space for menu items and
  351. X *   their associated IntuiText structures
  352. X */
  353. Xstruct MenuItem DModeItem[DMODEMAX];
  354. Xstruct IntuiText DModeText[DMODEMAX];
  355. X
  356. X/*****************************************************************/
  357. X/*    The following function initializes the structure arrays    */
  358. X/*   needed to provide the DrawMode menu topic.                  */
  359. X/*****************************************************************/
  360. XInitDModeItems()
  361. X   {
  362. X   short n;
  363. X
  364. X   /* initialize each meu item and IntuiText with loop */
  365. X   for( n=0; n<DMODEMAX; n++ )
  366. X      {
  367. X      DModeItem[n].NextItem = &DModeItem[n+1];
  368. X      DModeItem[n].LeftEdge = 0;
  369. X      DModeItem[n].TopEdge = 10 * n;
  370. X      DModeItem[n].Width = 112;
  371. X      DModeItem[n].Height = 10;
  372. X      DModeItem[n].Flags = ITEMTEXT | ITEMENABLED | HIGHBOX;
  373. X      DModeItem[n].MutualExclude = 0;
  374. X      DModeItem[n].ItemFill = (APTR)&DModeText[n];
  375. X      DModeItem[n].SelectFill = NULL;
  376. X      DModeItem[n].Command = 0;
  377. X      DModeItem[n].SubItem = NULL;
  378. X      DModeItem[n].NextSelect = 0;
  379. X
  380. X      DModeText[n].FrontPen = 0;
  381. X      DModeText[n].BackPen = 1;
  382. X      DModeText[n].DrawMode = JAM2;     /* render in fore and background */
  383. X      DModeText[n].LeftEdge = 0;
  384. X      DModeText[n].TopEdge = 1;
  385. X      DModeText[n].ITextFont = NULL;
  386. X      DModeText[n].NextText = NULL;
  387. X      }
  388. X   DModeItem[DMODEMAX-1].NextItem = NULL;
  389. X
  390. X   /* initialize text for specific menu items */
  391. X   DModeText[0].IText = (UBYTE *)"Erase All";
  392. X   DModeText[1].IText = (UBYTE *)"Hollow Box";
  393. X   DModeText[2].IText = (UBYTE *)"Filled Box";
  394. X   DModeText[3].IText = (UBYTE *)"Pen Draw";
  395. X
  396. X   return( 0 );
  397. X   }
  398. X
  399. X
  400. X/***************************************************/
  401. X/*                Menu Definition                  */
  402. X/*                                                 */
  403. X/*      This section of code is where the simple   */
  404. X/*   menu definition goes.  For now it supports    */
  405. X/*   only Color and Drawmode selection, but new    */
  406. X/*   choices can easily be added by creating       */
  407. X/*   structures and initializations functions      */
  408. X/*   similar to those provided above.              */
  409. X/***************************************************/
  410. X
  411. X/* current number of available menu topics */
  412. X#define MAXMENU 2
  413. X
  414. X/*   declaration of menu structure array for
  415. X *   number of current topics.  Intuition
  416. X *   will use the address of this array to
  417. X *   set and clear the menus associated with
  418. X *   the window.
  419. X */
  420. Xstruct Menu menu[MAXMENU];
  421. X
  422. X/**********************************************************************/
  423. X/*   The following function initializes the Menu structure array with */
  424. X/*  appropriate values for our simple menu strip.  Review the manual  */
  425. X/*  if you need to know what each value means.                        */
  426. X/**********************************************************************/
  427. XInitMenu()
  428. X   {
  429. X   menu[0].NextMenu = &menu[1];
  430. X   menu[0].LeftEdge = 10;
  431. X   menu[0].TopEdge = 0;
  432. X   menu[0].Width = 50;
  433. X   menu[0].Height = 10;
  434. X   menu[0].Flags = MENUENABLED;
  435. X   menu[0].MenuName = "Color";           /* text for menu-bar display */
  436. X   menu[0].FirstItem = &coloritem[0];    /* pointer to first item in list */
  437. X
  438. X   menu[1].NextMenu = NULL;
  439. X   menu[1].LeftEdge = 65;
  440. X   menu[1].TopEdge = 0;
  441. X   menu[1].Width = 85;
  442. X   menu[1].Height = 10;
  443. X   menu[1].Flags = MENUENABLED;
  444. X   menu[1].MenuName = "DrawMode";        /* text for menu-bar display */
  445. X   menu[1].FirstItem = &DModeItem[0];    /* pointer to first item in list */
  446. X
  447. X   return( 0 );
  448. X   }
  449. X
  450. X
  451. X/******************************************************/
  452. X/*                   Main Program                     */
  453. X/*                                                    */
  454. X/*      This is the main body of the program.         */
  455. X/******************************************************/
  456. X
  457. Xstruct Window *Window;              /* ptr to applications window */
  458. XSHORT MinX, MinY, MaxX, MaxY;       /* clipping boundary variables */
  459. XSHORT KeepGoing = TRUE;             /* main loop control value */
  460. X
  461. Xmain(argc, argv)
  462. Xint argc ;
  463. Xchar *argv[] ;
  464. X   {
  465. X   struct Library *OpenLibrary() ;
  466. X   struct Window *OpenWindow() ;
  467. X   struct Message *GetMsg() ;
  468. X   struct IntuiMessage *NewMessage;    /* msg structure for GetMsg() */
  469. X   BYTE DrawColor = 1;                 /* initial drawing color */
  470. X   SHORT OldBRX = 30, OldBRY = 30;     /* point coords used for boxes */
  471. X   SHORT TLX = 20, TLY = 20;           /* initial top-left point coords */
  472. X   ULONG class;                        /* used in message monitor loop */
  473. X   USHORT code;                        /* used in message monitor loop */
  474. X   SHORT x, y, x1, y1, x2, y2;         /* various coordinate variables */
  475. X   USHORT MenuNum, ItemNum;
  476. X   /*   The following is a set of declarations
  477. X    *   for a number of flag values used by the
  478. X    *   program.  These would perhaps be better
  479. X    *   coded as a bit-field for all the flags,
  480. X    *   but I'm lazy, and this is easier.
  481. X    */
  482. X   SHORT MouseMoved = FALSE;     /* indicates new mouse position ready */
  483. X   SHORT ClipIt = FALSE;         /* are new point coords out of bounds? */
  484. X   SHORT ClippedLast = FALSE;    /* was last PenDraw operation clipped? */
  485. X   SHORT PenMode = FALSE;        /* indicates PenDraw mode is set */      
  486. X   SHORT PenDown = FALSE;        /* if mouse moved, then should it draw? */
  487. X   SHORT RubberBox = FALSE;      /* are we currently rubberbanding a box? */
  488. X   SHORT FilledBox = FALSE;      /* should boxes be filled when drawn? */
  489. X#ifdef TALKTOREXX
  490. X/*
  491. X *   If we are talking to REXX, we need these two additional locals.
  492. X */
  493. X   long rexxbit ;
  494. X   char firstcommand[256] ;
  495. X#endif
  496. X
  497. X   /* attempt to Open Library to access Intuition */
  498. X   IntuitionBase = (struct IntuitionBase *)
  499. X      OpenLibrary("intuition.library", INTUITION_REV);
  500. X   if( IntuitionBase == NULL )
  501. X      exit(FALSE);
  502. X
  503. X   /* attempt to OpenLibrary to access Graphics functions */
  504. X   GfxBase = (struct GfxBase *)
  505. X      OpenLibrary("graphics.library",GRAPHICS_REV);
  506. X   if( GfxBase == NULL )
  507. X      exit(FALSE);
  508. X
  509. X
  510. X   /* Try to open new window for application */
  511. X   if(( Window = OpenWindow(&NewWindow) ) == NULL)
  512. X      exit(FALSE);
  513. X
  514. X   /*   set initial clipping boundaries
  515. X    *   from the values found in the window
  516. X    *   structure for border dimensions
  517. X    */
  518. X   MinX = Window->BorderLeft;
  519. X   MinY = Window->BorderTop;
  520. X   MaxX = Window->Width - Window->BorderRight - 1;
  521. X   MaxY = Window->Height - Window->BorderBottom - 1;
  522. X
  523. X   InitColorItems( 2 );         /* initialize Color menu arrays */
  524. X   InitDModeItems();            /* initialize DrawMode menu arrays */
  525. X   InitMenu();                  /* initialize the menu structures */
  526. X
  527. X   /*   Now, having initialized the various arrays
  528. X    *   of structures required for menu generation
  529. X    *   we can tell Intuition to make our menus
  530. X    *   available to the user when this window
  531. X    *   is active.
  532. X    */
  533. X   SetMenuStrip( Window, &menu[0] );
  534. X
  535. X   /* set initial drw mode and color */
  536. X   SetDrMd( Window->RPort, JAM1 );
  537. X   SetAPen( Window->RPort, DrawColor );
  538. X#ifdef TALKTOREXX
  539. X/*
  540. X *   For rexx, we open up a Rexx port, and send out the first command,
  541. X *   if there was one.  We send it out asynchronously; no reason not to.
  542. X */
  543. X   rexxbit = upRexxPort("freedraw", rcl, "fd", &disp) ;
  544. X   firstcommand[0] = 0 ;
  545. X   for (x=1; x<argc; x++) {
  546. X      strcat(firstcommand, argv[x]) ;
  547. X      strcat(firstcommand, " ") ;
  548. X   }
  549. X   if (firstcommand[0]) {
  550. X      asyncRexxCmd(firstcommand) ;
  551. X   }
  552. X#endif
  553. X   /*   Everything the program needs is now
  554. X    *   initialized and put in place.  The
  555. X    *   program enters the following loop
  556. X    *   and processes message continuously as
  557. X    *   they are received from Intuition.
  558. X    *      I guess this loop is the real workhorse
  559. X    *   of the program.  By the way, the loop
  560. X    *   control variable KeepGoing remains TRUE
  561. X    *   until a CLOSEWINDOW message is received.
  562. X    *   At that point it goes FALSE, and the
  563. X    *   program cleans up and exits.
  564. X    */
  565. X   while( KeepGoing )
  566. X      {
  567. X
  568. X      /* stay here until a message is received from Intuition */
  569. X#ifdef TALKTOREXX
  570. X/*
  571. X *   If we're working with Rexx, we wait on the Rexx bit as well.
  572. X *   Then, we handle any Rexx messages.
  573. X */
  574. X      Wait( (1L << Window->UserPort->mp_SigBit) | rexxbit);
  575. X      dispRexxPort() ;
  576. X#else
  577. X      Wait( 1L << Window->UserPort->mp_SigBit);
  578. X#endif
  579. X      MouseMoved = FALSE;    /* clear this flag each time thru loop */
  580. X
  581. X      /*   since more than one message may be waiting
  582. X       *   a reply at this point, a loop is used to
  583. X       *   process all that have come in until no more
  584. X       *   are ready.  Msg received is assigned to
  585. X       *   NewMessage from the GetMsg() function.  This
  586. X       *   value will be NULL if no message is ready,
  587. X       *   and control passes out of the loop at that time
  588. X       */
  589. X      while( NewMessage=(struct IntuiMessage *)GetMsg(Window->UserPort) )
  590. X         {
  591. X
  592. X         /*   copy some values from the message structure
  593. X          *   to variables used in the switch statements
  594. X          *   below
  595. X          */
  596. X         class = NewMessage->Class;
  597. X         code = NewMessage->Code;
  598. X         x = Window->MouseX;
  599. X         y = Window->MouseY;
  600. X
  601. X         /*   SIZEVERIFY is a very high priority message
  602. X          *   in our loop and requires some immediate
  603. X          *   servicing.  Any outstanding draw operations
  604. X          *   are immediately cancelled, and the DrawMode
  605. X          *   is nulled.  This prevents any attempts to
  606. X          *   render outside whatever new Window boundaries
  607. X          *   the user chooses.
  608. X          *
  609. X          *   (not anymore, it don't.  -tgr)
  610. X
  611. X         if( class == SIZEVERIFY )
  612. X            {
  613. X            PenDown = FALSE;
  614. X            if( RubberBox )
  615. X               {
  616. X               DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
  617. X               Window->Flags &= ( 0xFFFFFFFF ^ RMBTRAP );
  618. X               RubberBox = FALSE;
  619. X               }
  620. X            }
  621. X          */
  622. X
  623. X         /*   we have all the information needed from
  624. X          *   the message, so we can now safely reply
  625. X          *   to it without losing data
  626. X          */
  627. X         ReplyMsg( NewMessage );
  628. X
  629. X         /*  Examine point coords from message received
  630. X          *  and set the clipping flag if out of bounds.
  631. X          *  If user was drawing in PenMode when message
  632. X          *  was received, then the ClippedLast flag
  633. X          *  should also be set to indicate this to the
  634. X          *  next draw operation.
  635. X          */
  636. X         if(ClipIt = ( x < MinX || x > MaxX || y < MinY || y > MaxY ))
  637. X            if( PenDown )
  638. X               ClippedLast = TRUE;
  639. X
  640. X
  641. X         /* enter switch on type of message received */
  642. X         switch( class )
  643. X         {
  644. X            case MOUSEMOVE:
  645. X               /*   Don't really do anything with this one
  646. X                *   until any other, more important, messages
  647. X                *   are received and processed.
  648. X                */
  649. X               MouseMoved = TRUE;
  650. X               break;
  651. X
  652. X            case NEWSIZE:
  653. X               /*  set new clipping boundaries */
  654. X               MinX = Window->BorderLeft;
  655. X               MinY = Window->BorderTop;
  656. X               MaxX = Window->Width - Window->BorderRight - 1;
  657. X               MaxY = Window->Height - Window->BorderBottom - 1;
  658. X               break;
  659. X
  660. X            case CLOSEWINDOW:
  661. X               /*   User is ready to quit, so indicate
  662. X                *   that execution should terminate
  663. X                *   with next iteration of the loop.
  664. X                */
  665. X               KeepGoing = FALSE;
  666. X               break;
  667. X
  668. X            case MOUSEBUTTONS:
  669. X               /*   A number of things could have happened
  670. X                *   here, and further examination of data
  671. X                *   received from message is needed to
  672. X                *   determine what action should be taken.
  673. X                *   The code variable holds important info
  674. X                *   about what actually caused the message
  675. X                *   to be sent in the first place.
  676. X                */
  677. X               switch ( code )
  678. X                  {
  679. X                  case SELECTUP:
  680. X                     /*   User was holding down the left button
  681. X                      *   and just released it.  The PenMode
  682. X                      *   flag variables are set accordingly.
  683. X                      *   The pen can no longer be down, and
  684. X                      *   ClippedLast is reset for next time.
  685. X                      */
  686. X                     PenDown = ClippedLast = FALSE;
  687. X                     break;
  688. X
  689. X                  case SELECTDOWN:
  690. X                     /*   User has pressed the left button, and
  691. X                      *   several differnt actions may need to
  692. X                      *   be taken.  If the ClipIt value is TRUE,
  693. X                      *   then no action should be taken at all.
  694. X                      */
  695. X                     if( ClipIt )
  696. X                        break;
  697. X
  698. X                     /*   If user is currently in PenMode, then
  699. X                      *   set up to draw when MOUSEMOVED messages
  700. X                      *   are received until a subsequent SELECTUP
  701. X                      *   message comes in.
  702. X                      */
  703. X                     if( PenMode )
  704. X                        {
  705. X                        PenDown = TRUE;
  706. X                        ClippedLast = FALSE;
  707. X
  708. X                        /* make sure to set appropriate mode */
  709. X                        SetDrMd( Window->RPort, JAM1 );
  710. X
  711. X                        /* and establish initial position to draw */
  712. X                        Move( Window->RPort, (long)x, (long)y );
  713. X                        break;
  714. X                        }
  715. X
  716. X                     /*   If user is currently rubberbanding a box,
  717. X                      *   then a SELECTDOWN message means it is time
  718. X                      *   to stop rubberbanding and actually draw it.
  719. X                      *   The following code will be executed if
  720. X                      *   this is the case, and it will determine if
  721. X                      *   a filled box is needed before rendering.
  722. X                      */
  723. X                     if( RubberBox )
  724. X                        {
  725. X                        /*   set draw mode back to JAM1 since
  726. X                         *   it is now currently set to COMPLEMENT
  727. X                         */
  728. X                        SetDrMd( Window->RPort, JAM1 );
  729. X                        RubberBox = FALSE;   /* turn off rubberbanding */
  730. X
  731. X                        /*   Restore the condition of the RMBTRAP
  732. X                         *   bit in the Window structure's Flags
  733. X                         *   member.  Menubutton events will no
  734. X                         *   be received by this loop.
  735. X                         */
  736. X                        Window->Flags &= ( 0xFFFFFFFF ^ RMBTRAP );
  737. X
  738. X                        /*   RectFill is not condusive to the smooth
  739. X                         *   execution of programs iit arguments are
  740. X                         *   out of order, sot his code sorts them
  741. X                         *   in preparation for the call.
  742. X                         */
  743. X                        if( FilledBox )
  744. X                           {
  745. X                           /* first sort the x-coords */
  746. X                           if( TLX < OldBRX )  {
  747. X                              x1 = TLX;  x2 = OldBRX;  }
  748. X                           else  {
  749. X                              x1 = OldBRX;  x2 = TLX;  }
  750. X
  751. X                           /* then sort the y-coords */
  752. X                           if( TLY < OldBRY )  {
  753. X                              y1 = TLY;  y2 = OldBRY;  }
  754. X                           else  {
  755. X                              y1 = OldBRY;  y2 = TLY;  }
  756. X
  757. X                           /* now generate the filled rectangle */
  758. X                           RectFill( Window->RPort, (long)x1, (long)y1,
  759. X                                                    (long)x2, (long)y2 );
  760. X                           }
  761. X                        else
  762. X                           {
  763. X                           /* FilledBox not set, so draw hollow box */
  764. X                           DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
  765. X                           }
  766. X                        break;
  767. X                        }
  768. X
  769. X                     /*   If execution comes here, then PenMode was
  770. X                      *   not set and user was not rubberbanding.
  771. X                      *   SELECTDOWN therefore indicates to start the
  772. X                      *   rubberbanding process at this point.  The
  773. X                      *   initial coords are set to the values we
  774. X                      *   received when the GetMsg() was executed.
  775. X                      */
  776. X                     TLX = OldBRX = x;  TLY = OldBRY = y;
  777. X
  778. X                     /* set to render in XOR mode */
  779. X                     SetDrMd( Window->RPort, COMPLEMENT );
  780. X
  781. X                     /* set flag to indicate we are now rubberbanding */
  782. X                     RubberBox = TRUE;
  783. X
  784. X                     /*   This instruction indicates to Intuition
  785. X                      *   that we now wish to receive a message
  786. X                      *   each time the Menubutton is pressed.
  787. X                      *   This is how we hijack the right button
  788. X                      *   for temporary use as a Cancel button
  789. X                      *   instead of a Menubutton.
  790. X                      */
  791. X                     Window->Flags |= RMBTRAP;
  792. X
  793. X                     /* render the initial rubberbox and exit */
  794. X                     DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
  795. X                     break;
  796. X
  797. X                  case MENUDOWN:
  798. X                     /*   WE only receive this message class if
  799. X                      *   the RMBTRAP flag bit has been set, so
  800. X                      *   it always means that we should cancel
  801. X                      *   the box which is currently rubberbanding.
  802. X                      */
  803. X                     /* turn the flag off */
  804. X                     RubberBox = FALSE;
  805. X
  806. X                     /* restore control of menubutton to Intuition */
  807. X                     Window->Flags &= ( 0xFFFFFFFF ^ RMBTRAP );
  808. X
  809. X                     /*   erase (by double XOR'ing) the current
  810. X                      *   rubberbox and exit switch.
  811. X                      */
  812. X                     DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
  813. X                     break;
  814. X
  815. X                  default:
  816. X                     /*   Something unimportant happened, so just
  817. X                      *   continue thru the GetMsg() loop.
  818. X                      */
  819. X                     continue;
  820. X               }
  821. X               break;
  822. X
  823. X            case MENUPICK:
  824. X               /*   A menu event has taken place and is
  825. X                *   ready to be processed.  Examine the
  826. X                *   code variable received from the message
  827. X                *   to determine what action should be taken.
  828. X                *   The first check is for MENUNULL, which
  829. X                *   means that nothing should be done at all.
  830. X                */
  831. X               if( code != MENUNULL )
  832. X                  {
  833. X                  /* get menu and item numbers from code */
  834. X                  MenuNum = MENUNUM( code );
  835. X                  ItemNum = ITEMNUM( code );
  836. X
  837. X                  /* determine appropriate action by menu number */
  838. X                  switch ( MenuNum )
  839. X                     {
  840. X                     case 0:
  841. X                        /*   Menu 0 is the Color menu.  The
  842. X                         *   item number indicates which new
  843. X                         *   color to set.
  844. X                         */
  845. X                        DrawColor = ItemNum;
  846. X                        SetAPen( Window->RPort, (long)DrawColor );
  847. X                        break;
  848. X
  849. X                     case 1:
  850. X                        /*   Menu 1 is the DrawMode menu.  The item
  851. X                         *   number indicates what to do.
  852. X                         *   NOTE:  Since we cannot have received
  853. X                         *   this message if we were rubberbanding,
  854. X                         *   then there is no need to clean up before
  855. X                         *   changing drawing modes.
  856. X                         */
  857. X                        switch ( ItemNum )
  858. X                           {
  859. X                           case 0:
  860. X                              /* Erase window to current color */
  861. X                              SetDrMd( Window->RPort, JAM1 );
  862. X                              RectFill( Window->RPort, (long)MinX, (long)MinY,
  863. X                                                       (long)MaxX, (long)MaxY);
  864. X                              break;
  865. X
  866. X                           case 1:
  867. X                              /* set flag variables for hollow box */
  868. X                              PenMode = FALSE;
  869. X                              FilledBox = FALSE;
  870. X                              break;
  871. X
  872. X                           case 2:
  873. X                              /* set flag variables for filled box */
  874. X                              PenMode = FALSE;
  875. X                              FilledBox = TRUE;
  876. X                              break;
  877. X
  878. X                           case 3:
  879. X                              /* set flag variables for PenMode */
  880. X                              PenMode = TRUE;
  881. X                              break;
  882. X
  883. X                           default:
  884. X                              /* don't do anything */
  885. X                              break;
  886. X                           }
  887. X                        break;
  888. X
  889. X                     default:
  890. X                        /* Menu number unrecognized, do nothing */
  891. X                        break;
  892. X                     }
  893. X                  }
  894. X               break;
  895. X
  896. X            case INACTIVEWINDOW:
  897. X               /*   User has de-selected our window, so a
  898. X                *   little bit of cleaning up may be needed
  899. X                *   to prevent untoward events when he comes
  900. X                *   back to it.
  901. X                */
  902. X               /* erase any outstanding rubberbox */
  903. X               if( RubberBox )
  904. X                  DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
  905. X
  906. X               /* reset all the flafg variables */
  907. X               PenDown = ClippedLast = RubberBox = FALSE;
  908. X
  909. X               /* return possibly diverted menubutton events to Big I */
  910. X               Window->Flags &= ( 0xFFFFFFFF ^ RMBTRAP );
  911. X               break;
  912. X
  913. X            default:
  914. X               /* message class was unrecognized, so do nothing */
  915. X               break;
  916. X            }
  917. X         }   /* this brace ends the while(NewMessage) loop way back when */
  918. X
  919. X      /*   There are no more messages waiting at the
  920. X       *   IDCMP port, so we can now proceed to
  921. X       *   process any MOUSEMOVED message we may
  922. X       *   have received.
  923. X       */
  924. X      if( MouseMoved && !ClipIt)
  925. X         {
  926. X         /* the mouse did move, and we don't need to clip */
  927. X
  928. X         /* check first if we are drawing in PenMode */
  929. X         if( PenDown )
  930. X            {
  931. X            /*   We have to examine if we clipped the
  932. X             *   last PenMode draw operation.  If we did,
  933. X             *   then this is the first move back into
  934. X             *   window boundaries, so we mov instead of
  935. X             *   drawing.
  936. X             */
  937. X            if( ClippedLast )
  938. X               {
  939. X               ClippedLast = FALSE;         /* reset this flag now */
  940. X               Move( Window->RPort, (long)x, (long)y );
  941. X               }
  942. X            else
  943. X               Draw( Window->RPort, (long)x, (long)y ); /* draw to x,y coords */
  944. X         }
  945. X         else
  946. X            {
  947. X            /*   We weren't in PenMode, but we still might
  948. X             *   be rubberbanding a box.  If so, then we
  949. X             *   should erase the current rubberbox and
  950. X             *   draw a new one with the new mouse coords.
  951. X             */
  952. X            if( RubberBox )
  953. X               {
  954. X               /* erase the old rubberbox - draw mode is COMPLEMENT */
  955. X               DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
  956. X
  957. X               /* assign new values to box coords */
  958. X               OldBRX = x;  OldBRY = y;
  959. X
  960. X               /* and draw the new rubberbox */ 
  961. X               DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
  962. X               }
  963. X            }
  964. X         }
  965. X      }
  966. X
  967. X   /*   It must be time to quit, so we have to clean
  968. X    *   up and exit.
  969. X    */
  970. X#ifdef TALKTOREXX
  971. X/*
  972. X *   With Rexx, we need to bring the port down.  You might make this
  973. X *   part of exit() for programs that have multiple paths to exit.
  974. X */
  975. X   dnRexxPort() ;
  976. X#endif
  977. X   ClearMenuStrip( Window );
  978. X   CloseWindow( Window );
  979. X   exit(TRUE);
  980. X   }
  981. X#ifdef TALKTOREXX
  982. X/*
  983. X *   Now we get into the actual code necessary for our REXX port; functions
  984. X *   that do the real work.  Note that this program was not structured
  985. X *   particularly nicely for Rexx; I had to write each of these functions.
  986. X *   Many programs have these subroutines already in place; they are called
  987. X *   as part of the event loop.  This progam, however, just has one big
  988. X *   switch statement with different actions . . .
  989. X *
  990. X *   First, our locals.
  991. X */
  992. Xint currrexxcolor = 1 ;    /* what color is *rexx* drawing in? */
  993. Xint args[4] ;              /* what args did we see to this function? */
  994. Xint parsed ;               /* was argument parsing successful? */
  995. Xint userreplied ;          /* has the current message been replied to yet? */
  996. X/*
  997. X *   This function takes a pointer to a pointer to a string, grabs the
  998. X *   next number, returns it, and advances the pointer to the string to
  999. X *   point after the number.
  1000. X */
  1001. Xint getnm(where)
  1002. Xchar **where ;
  1003. X{
  1004. X   register char *p = *where ;
  1005. X   register int val = 0 ;
  1006. X   int gotone = 0 ;
  1007. X
  1008. X   while (*p <= ' ' && *p)
  1009. X      p++ ;
  1010. X   while ('0' <= *p && *p <= '9') {
  1011. X      gotone = 1 ;
  1012. X      val = 10 * val + *p++ - '0' ;
  1013. X   }
  1014. X   if (gotone == 0)
  1015. X      parsed = 0 ;
  1016. X   *where = p ;
  1017. X   return(val) ;
  1018. X}
  1019. X/*
  1020. X *   This function trys to find `n' numeric arguments in the command
  1021. X *   string, and stuffs them into the args array.
  1022. X */
  1023. Xvoid parseargs(p, n)
  1024. Xchar *p ;
  1025. Xint n ;
  1026. X{
  1027. X   register int i ;
  1028. X
  1029. X   while (*p > ' ' && *p)
  1030. X      p++ ;
  1031. X   for (i=0; i<n; i++)
  1032. X      args[i] = getnm(&p) ;
  1033. X}
  1034. X/*
  1035. X *   This is our main dispatch function.  We check to make sure a Window
  1036. X *   currently exists.  Then, we store away the `current color' and change
  1037. X *   it to Rexx's current color, call our handler function, and then restore
  1038. X *   the color.  If our handler replied, we return a 1 to indicate that.
  1039. X *   If the parse and everything else was successful, we return a 0.
  1040. X *   Otherwise, we return a failure of 20 to indicate that the arguments
  1041. X *   were messed up.
  1042. X */
  1043. Xint disp(msg, dat, p)
  1044. Xregister struct RexxMsg *msg ;
  1045. Xregister struct rexxCommandList *dat ;
  1046. Xchar *p ;
  1047. X{
  1048. X   register int t ;
  1049. X
  1050. X   parsed = 1 ;
  1051. X   if (Window) {
  1052. X      userreplied = 0 ;
  1053. X      t = Window->RPort->FgPen ;
  1054. X      SetAPen(Window->RPort, (long)currrexxcolor) ;
  1055. X      ((int (*)())(dat->userdata))(msg, p) ;
  1056. X      SetAPen(Window->RPort, (long)t) ;
  1057. X      if (! parsed)
  1058. X         replyRexxCmd(msg, (long)parsed, 0L, NULL) ;
  1059. X      return ;
  1060. X   }
  1061. X   replyRexxCmd(msg, 20L, 10L, NULL) ;
  1062. X}
  1063. X/*
  1064. X *   This handler sets the current rexx color.
  1065. X */
  1066. Xvoid rexxcolor(msg, p)
  1067. Xstruct RexxMsg *msg ;
  1068. Xchar *p ;
  1069. X{
  1070. X   parseargs(p, 1) ;
  1071. X   currrexxcolor = args[0] ;
  1072. X}
  1073. X/*
  1074. X *   This function silently clips the x and y values at `n' to the
  1075. X *   window bounds.
  1076. X */
  1077. Xvoid clipxy(n)
  1078. Xint n ;
  1079. X{
  1080. X   if (args[n] < MinX)
  1081. X      args[n] = MinX ;
  1082. X   if (args[n] > MaxX)
  1083. X      args[n] = MaxX ;
  1084. X   n++ ;
  1085. X   if (args[n] < MinY)
  1086. X      args[n] = MinY ;
  1087. X   if (args[n] > MaxY)
  1088. X      args[n] = MaxY ;
  1089. X}
  1090. X/*
  1091. X *   This handler grabs four arguments and draws a box.
  1092. X */
  1093. Xvoid rexxbox(msg, p)
  1094. Xstruct RexxMsg *msg ;
  1095. Xchar *p ;
  1096. X{
  1097. X   parseargs(p, 4) ;
  1098. X   clipxy(0) ;
  1099. X   clipxy(2) ;
  1100. X   DrawBox(args[0], args[1], args[2], args[3], Window, currrexxcolor) ;
  1101. X}
  1102. X/*
  1103. X *   This handler grabs four arguments and draws a filled box.
  1104. X */
  1105. Xvoid rexxfbox(msg, p)
  1106. Xstruct RexxMsg *msg ;
  1107. Xchar *p ;
  1108. X{
  1109. X   register int t ;
  1110. X
  1111. X   parseargs(p, 4) ;
  1112. X   clipxy(0) ;
  1113. X   clipxy(2) ;
  1114. X   if (args[0] > args[2]) {
  1115. X      t = args[0] ; args[0] = args[2] ; args[2] = t ;
  1116. X   }
  1117. X   if (args[1] > args[3]) {
  1118. X      t = args[1] ; args[1] = args[3] ; args[3] = t ;
  1119. X   }
  1120. X   RectFill( Window->RPort, (long)args[0], (long)args[1],
  1121. X                            (long)args[2], (long)args[3]) ;
  1122. X}
  1123. X/*
  1124. X *   This handler grabs four arguments and draws a line.
  1125. X */
  1126. Xvoid rexxline(msg, p)
  1127. Xstruct RexxMsg *msg ;
  1128. Xchar *p ;
  1129. X{
  1130. X   parseargs(p, 4) ;
  1131. X   clipxy(0) ;
  1132. X   clipxy(2) ;
  1133. X   Move(Window->RPort, (long)args[0], (long)args[1]) ;
  1134. X   Draw(Window->RPort, (long)args[2], (long)args[3]) ;
  1135. X}
  1136. X/*
  1137. X *   This handler pops the window to front.
  1138. X */
  1139. Xvoid rexxtofront(msg, p)
  1140. Xstruct RexxMsg *msg ;
  1141. Xchar *p ;
  1142. X{
  1143. X   WindowToFront(Window) ;
  1144. X}
  1145. X/*
  1146. X *   This handler pops the window to back.
  1147. X */
  1148. Xvoid rexxtoback(msg, p)
  1149. Xstruct RexxMsg *msg ;
  1150. Xchar *p ;
  1151. X{
  1152. X   WindowToBack(Window) ;
  1153. X}
  1154. X/*
  1155. X *   This handler sets the exit flag.
  1156. X */
  1157. Xvoid rexxexit(msg, p)
  1158. Xstruct RexxMsg *msg ;
  1159. Xchar *p ;
  1160. X{
  1161. X   KeepGoing = 0 ;
  1162. X}
  1163. X/*
  1164. X *   This handler returns the version of the program.
  1165. X */
  1166. Xvoid rexxversion(msg, p)
  1167. Xstruct RexxMsg *msg ;
  1168. Xchar *p ;
  1169. X{
  1170. X   userreplied = 1 ;
  1171. X   replyRexxCmd(msg, 0L, 0L, VERSION) ;
  1172. X}
  1173. X/*
  1174. X *   This handler sends the rest of the command asynchronously,
  1175. X *   allowing us to run macros in parallel.
  1176. X */
  1177. Xvoid rexxspawn(msg, p)
  1178. Xstruct RexxMsg *msg ;
  1179. Xchar *p ;
  1180. X{
  1181. X   while (*p <= ' ' && *p)
  1182. X      p++ ;
  1183. X   asyncRexxCmd(p) ;
  1184. X}
  1185. X#endif
  1186. SHAR_EOF
  1187. echo "extracting minrexx.c"
  1188. sed 's/^X//' << \SHAR_EOF > minrexx.c
  1189. X/*
  1190. X *   This is an example of how REXX messages might be handled.  This is
  1191. X *   a `minimum' example that both accepts asynchronous REXX messages and
  1192. X *   can request REXX service.
  1193. X *
  1194. X *   Read this entire file!  It's short enough.
  1195. X *
  1196. X *   It is written in such a fashion that it can be attached to a program
  1197. X *   with a minimum of fuss.  The only external symbols it makes available
  1198. X *   are the seven functions and RexxSysBase.
  1199. X *
  1200. X *   This code is by Radical Eye Software, but it is put in the public
  1201. X *   domain.  I would appreciate it if the following string was left in
  1202. X *   both as a version check and as thanks from you for the use of this
  1203. X *   code.
  1204. X *
  1205. X *   If you modify this file for your own use, don't bump the version
  1206. X *   number; add a suffix, such as 1.0a or 1.0.3 or something, so we
  1207. X *   don't have fake `versions' floating around.
  1208. X */
  1209. Xstatic char *blurb = "Radical Eye MinRexx 0.4" ;
  1210. X/*
  1211. X *   We read in our own personal little include.
  1212. X */
  1213. X#include "minrexx.h"
  1214. X/*
  1215. X *   All of our local globals, hidden from sight.
  1216. X */
  1217. Xstatic struct MsgPort *rexxPort ;          /* this is *our* rexx port */
  1218. Xstatic int bringerdown ;                   /* are we trying to shut down? */
  1219. Xstatic struct rexxCommandList *globalrcl ; /* our command association list */
  1220. Xstatic long stillNeedReplies ;             /* how many replies are pending? */
  1221. Xstatic long rexxPortBit ;                  /* what bit to wait on for Rexx? */
  1222. Xstatic char *extension ;                   /* the extension for macros */
  1223. Xstatic int (*userdisp)() ;                 /* the user's dispatch function */
  1224. Xstatic struct RexxMsg *oRexxMsg ;          /* the outstanding Rexx message */
  1225. X/*
  1226. X *   Our library base.  Don't you dare close this!
  1227. X */
  1228. Xstruct RxsLib *RexxSysBase ;
  1229. X/*
  1230. X *   This is the main entry point into this code.
  1231. X */
  1232. Xlong upRexxPort(s, rcl, exten, uf)
  1233. X/*
  1234. X *   The first argument is the name of your port to be registered;
  1235. X *   this will be used, for instance, with the `address' command of ARexx.
  1236. X */
  1237. Xchar *s ;
  1238. X/*
  1239. X *   The second argument is an association list of command-name/user-data
  1240. X *   pairs.  It's an array of struct rexxCommandList, terminated by a
  1241. X *   structure with a NULL in the name field. The commands are case
  1242. X *   sensitive.  The user-data field can contain anything appropriate,
  1243. X *   perhaps a function to call or some other data.
  1244. X */
  1245. Xstruct rexxCommandList *rcl ;
  1246. X/*
  1247. X *   The third argument is the file extension for ARexx macros invoked
  1248. X *   by this program.  If you supply this argument, any `primitive' not
  1249. X *   in the association list rcl will be sent out to ARexx for
  1250. X *   interpretation, thus allowing macro programs to work just like
  1251. X *   primitives.  If you do not want this behavior, supply a `NULL'
  1252. X *   here, and those commands not understood will be replied with an
  1253. X *   error value of RXERRORNOCMD.
  1254. X */
  1255. Xchar *exten ;
  1256. X/*
  1257. X *   The fourth argument is the user dispatch function.  This function
  1258. X *   will *only* be called from rexxDisp(), either from the user calling
  1259. X *   this function directly, or from dnRexxPort().  Anytime a command
  1260. X *   match is found in the association list, this user-supplied function
  1261. X *   will be called with two arguments---the Rexx message that was
  1262. X *   received, and a pointer to the association pair.  This function
  1263. X *   should return a `1' if the message was replied to by the function
  1264. X *   and a `0' if the default success code of (0, 0) should be returned.
  1265. X *   Note that the user function should never ReplyMsg() the message;
  1266. X *   instead he should indicate the return values with replyRexxCmd();
  1267. X *   otherwise we lose track of the messages that still lack replies.
  1268. X */
  1269. Xint (*uf)() ;
  1270. X/*
  1271. X *   upRexxPort() returns the signal bit to wait on for Rexx messages.
  1272. X *   If something goes wrong, it simply returns a `0'.  Note that this
  1273. X *   function is safe to call multiple times because we check to make
  1274. X *   sure we haven't opened already.  It's also a quick way to change
  1275. X *   the association list or dispatch function.
  1276. X */
  1277. X{
  1278. X   struct MsgPort *FindPort() ;
  1279. X   struct MsgPort *CreatePort() ;
  1280. X
  1281. X/*
  1282. X *   Some basic error checking.
  1283. X */
  1284. X   if (rcl == NULL || uf == NULL)
  1285. X      return(0L) ;
  1286. X/*
  1287. X *   If we aren't open, we make sure no one else has opened a port with
  1288. X *   this name already.  If that works, and the createport succeeds, we
  1289. X *   fill rexxPortBit with the value to return.
  1290. X *
  1291. X *   Note that rexxPortBit will be 0 iff rexxPort is NULL, so the check
  1292. X *   for rexxPort == NULL also insures that our rexxPortBit is 0.
  1293. X */
  1294. X   if (rexxPort == NULL) {
  1295. X      Forbid() ;
  1296. X      if (FindPort(s)==NULL)
  1297. X         rexxPort = CreatePort(s, 0L) ;
  1298. X      Permit() ;
  1299. X      if (rexxPort != NULL)
  1300. X         rexxPortBit = 1L << rexxPort->mp_SigBit ;
  1301. X   }
  1302. X/*
  1303. X *   Squirrel away these values for our own internal access, and return
  1304. X *   the wait bit.
  1305. X */
  1306. X   globalrcl = rcl ;
  1307. X   extension = exten ;
  1308. X   userdisp = uf ;
  1309. X   return(rexxPortBit) ;
  1310. X}
  1311. X/*
  1312. X *   This function closes the rexx library, but only if it is open
  1313. X *   and we aren't expecting further replies from REXX.  It's
  1314. X *   *private*, but it doesn't have to be; it's pretty safe to
  1315. X *   call anytime.
  1316. X */
  1317. Xstatic void closeRexxLib() {
  1318. X   if (stillNeedReplies == 0 && RexxSysBase) {
  1319. X      CloseLibrary(RexxSysBase) ;
  1320. X      RexxSysBase = NULL ;
  1321. X   }
  1322. X}
  1323. X/*
  1324. X *   This function closes down the Rexx port.  It is always safe to
  1325. X *   call, and should *definitely* be made a part of your cleanup
  1326. X *   routine.  No arguments and no return.  It removes the Rexx port,
  1327. X *   replies to all of the messages and insures that we get replies
  1328. X *   to all the ones we sent out, closes the Rexx library, deletes the
  1329. X *   port, clears a few flags, and leaves.
  1330. X */
  1331. Xvoid dnRexxPort() {
  1332. X   if (rexxPort) {
  1333. X      RemPort(rexxPort) ;
  1334. X      bringerdown = 1 ;
  1335. X/*
  1336. X *   A message still hanging around?  We kill it off.
  1337. X */
  1338. X      if (oRexxMsg) {
  1339. X         oRexxMsg->rm_Result1 = RXERRORIMGONE ;
  1340. X         ReplyMsg(oRexxMsg) ;
  1341. X         oRexxMsg = NULL ;
  1342. X      }
  1343. X      while (stillNeedReplies) {
  1344. X         WaitPort(rexxPort) ;
  1345. X         dispRexxPort() ;
  1346. X      }
  1347. X      closeRexxLib() ;
  1348. X      DeletePort(rexxPort) ;
  1349. X      rexxPort = NULL ;
  1350. X   }
  1351. X   rexxPortBit = 0 ;
  1352. X}
  1353. X/*
  1354. X *   Here we dispatch any REXX messages that might be outstanding.
  1355. X *   This is the main routine for handling Rexx messages.
  1356. X *   This function is fast if no messages are outstanding, so it's
  1357. X *   pretty safe to call fairly often.
  1358. X *
  1359. X *   If we are bring the system down and flushing messages, we reply
  1360. X *   with a pretty serious return code RXERRORIMGONE.
  1361. X *
  1362. X *   No arguments, no returns.
  1363. X */
  1364. Xvoid dispRexxPort() {
  1365. X   register struct RexxMsg *GetMsg() ;
  1366. X   register struct RexxMsg *RexxMsg ;
  1367. X   int cmdcmp() ;
  1368. X   register struct rexxCommandList *rcl ;
  1369. X   register char *p ;
  1370. X   register int dontreply ;
  1371. X
  1372. X/*
  1373. X *   If there's no rexx port, we're out of here.
  1374. X */
  1375. X   if (rexxPort == NULL)
  1376. X      return ;
  1377. X/*
  1378. X *   Otherwise we have our normal loop on messages.
  1379. X */
  1380. X   while (RexxMsg = (struct RexxMsg *)GetMsg(rexxPort)) {
  1381. X/*
  1382. X *   If we have a reply to a message we sent, we look at the second
  1383. X *   argument.  If it's set, it's a function we are supposed to call
  1384. X *   so we call it.  Then, we kill the argstring and the message
  1385. X *   itself, decrement the outstanding count, and attempt to close
  1386. X *   down the Rexx library.  Note that this call only succeeds if
  1387. X *   there are no outstanding messages.  Also, it's pretty quick, so
  1388. X *   don't talk to me about efficiency.
  1389. X */
  1390. X      if (RexxMsg->rm_Node.mn_Node.ln_Type == NT_REPLYMSG) {
  1391. X         if (RexxMsg->rm_Args[1]) {
  1392. X            ((int (*)())(RexxMsg->rm_Args[1]))(RexxMsg) ;
  1393. X         }
  1394. X         DeleteArgstring(RexxMsg->rm_Args[0]) ;
  1395. X         DeleteRexxMsg(RexxMsg) ;
  1396. X         stillNeedReplies-- ;
  1397. X         closeRexxLib() ;
  1398. X/*
  1399. X *   The default case is we got a message and we need to check it for
  1400. X *   primitives.  We skip past any initial tabs or spaces and initialize
  1401. X *   the return code fields.
  1402. X */
  1403. X      } else {
  1404. X         p = (char *)RexxMsg->rm_Args[0] ;
  1405. X         while (*p > 0 && *p <= ' ')
  1406. X            p++ ;
  1407. X         RexxMsg->rm_Result1 = 0 ;
  1408. X         RexxMsg->rm_Result2 = 0 ;
  1409. X/*
  1410. X *   If somehow the reply is already done or postponed, `dontreply' is
  1411. X *   set.
  1412. X */
  1413. X         dontreply = 0 ;
  1414. X/*
  1415. X *   If the sky is falling, we just blow up and replymsg.
  1416. X */
  1417. X         if (bringerdown) {
  1418. X            RexxMsg->rm_Result1 = RXERRORIMGONE ;
  1419. X/*
  1420. X *   Otherwise we cdr down our association list, comparing commands,
  1421. X *   until we get a match.  If we get a match, we call the dispatch
  1422. X *   function with the appropriate arguments, and break out.
  1423. X */
  1424. X         } else {
  1425. X            oRexxMsg = RexxMsg ;
  1426. X            for (rcl = globalrcl; rcl->name; rcl++) {
  1427. X               if (cmdcmp(rcl->name, p) == 0) {
  1428. X                  userdisp(RexxMsg, rcl, p+strlen(rcl->name)) ;
  1429. X                  break ;
  1430. X               }
  1431. X            }
  1432. X/*
  1433. X *   If we broke out, rcl will point to the command we executed; if we
  1434. X *   are at the end of the list, we didn't understand the command.  In
  1435. X *   this case, if we were supplied an extension in upRexxPort, we know
  1436. X *   that we should send the command out, so we do so, synchronously.
  1437. X *   The synchronous send takes care of our reply.  If we were given a
  1438. X *   NULL extension, we bitch that the command didn't make sense to us.
  1439. X */
  1440. X            if (rcl->name == NULL) {
  1441. X               if (extension) {
  1442. X                  syncRexxCmd(RexxMsg->rm_Args[0], RexxMsg) ;
  1443. X                  dontreply = 1 ;
  1444. X               } else {
  1445. X                  RexxMsg->rm_Result1 = RXERRORNOCMD ;
  1446. X               }
  1447. X            }
  1448. X         }
  1449. X/*
  1450. X *   Finally, reply if appropriate.
  1451. X */
  1452. X         oRexxMsg = NULL ;
  1453. X         if (! dontreply)
  1454. X            ReplyMsg(RexxMsg) ;
  1455. X      }
  1456. X   }
  1457. X}
  1458. X/*
  1459. X *   This is the function we use to see if the command matches
  1460. X *   the command string.  Not case sensitive, and the real command only
  1461. X *   need be a prefix of the command string.  Make sure all commands
  1462. X *   are given in lower case!
  1463. X */
  1464. Xstatic int cmdcmp(c, m)
  1465. Xregister char *c, *m ;
  1466. X{
  1467. X   while (*c && ((*c == *m) || (*c == *m + 32 && ('a' <= *c && *c <= 'z')))) {
  1468. X      c++ ;
  1469. X      m++ ;
  1470. X   }
  1471. X   return(*c) ;
  1472. X}
  1473. X/*
  1474. X *   Opens the Rexx library if unopened.  Returns success (1) or
  1475. X *   failure (0).  This is another function that is *private* but
  1476. X *   that doesn't have to be.
  1477. X */
  1478. Xstatic int openRexxLib() {
  1479. X   struct RxsLib *OpenLibrary() ;
  1480. X
  1481. X   if (RexxSysBase)
  1482. X      return(1) ;
  1483. X   return((RexxSysBase = OpenLibrary(RXSNAME, 0L)) != NULL) ;
  1484. X}
  1485. X/*
  1486. X *   This is the general ARexx command interface, but is not the one
  1487. X *   you will use most of the time; ones defined later are easier to
  1488. X *   understand and use.  But they all go through here.
  1489. X */
  1490. Xstruct RexxMsg *sendRexxCmd(s, f, p1, p2, p3)
  1491. Xchar *s ;
  1492. X/*
  1493. X *   The first parameter is the command to send to Rexx.
  1494. X */
  1495. Xint (*f)() ;
  1496. X/*
  1497. X *   The second parameter is either NULL, indicating that the command
  1498. X *   should execute asynchronously, or a function to be called when the
  1499. X *   message we build up and send out here finally returns.  Please note
  1500. X *   that the function supplied here could be called during cleanup after
  1501. X *   a fatal error, so make sure it is `safe'.  This function always is
  1502. X *   passed one argument, the RexxMsg that is being replied.
  1503. X */
  1504. XSTRPTR p1, p2, p3 ;
  1505. X/*
  1506. X *   These are up to three arguments to be stuffed into the RexxMsg we
  1507. X *   are building up, making the values available when the message is
  1508. X *   finally replied to.  The values are stuffed into Args[2]..Args[4].
  1509. X */
  1510. X{
  1511. X   struct RexxMsg *CreateRexxMsg() ;
  1512. X   STRPTR CreateArgstring() ;
  1513. X   register struct MsgPort *rexxport ;
  1514. X   register struct RexxMsg *RexxMsg ;
  1515. X
  1516. X/*
  1517. X *   If we have too many replies out there, we just return failure.
  1518. X *   Note that you should check the return code to make sure your
  1519. X *   message got out!  Then, we forbid, and make sure that:
  1520. X *      - we have a rexx port open
  1521. X *      - Rexx is out there
  1522. X *      - the library is open
  1523. X *      - we can create a message
  1524. X *      - we can create an argstring
  1525. X *
  1526. X *   If all of these succeed, we stuff a few values and send the
  1527. X *   message, permit, and return.
  1528. X */
  1529. X   if (rexxPort == NULL || stillNeedReplies > MAXRXOUTSTANDING-1)
  1530. X      return(NULL) ;
  1531. X   RexxMsg = NULL ;
  1532. X   if (openRexxLib() && (RexxMsg =
  1533. X             CreateRexxMsg(rexxPort, extension, rexxPort->mp_Node.ln_Name)) &&
  1534. X             (RexxMsg->rm_Args[0] = CreateArgstring(s, (long)strlen(s)))) {
  1535. X      RexxMsg->rm_Action = RXCOMM ;
  1536. X      RexxMsg->rm_Args[1] = (STRPTR)f ;
  1537. X      RexxMsg->rm_Args[2] = p1 ;
  1538. X      RexxMsg->rm_Args[3] = p2 ;
  1539. X      RexxMsg->rm_Args[4] = p3 ;
  1540. X      RexxMsg->rm_Node.mn_Node.ln_Name = RXSDIR ;
  1541. X      Forbid() ;
  1542. X      if (rexxport = FindPort(RXSDIR))
  1543. X         PutMsg(rexxport, RexxMsg) ;
  1544. X      Permit() ;
  1545. X      if (rexxport) {
  1546. X         stillNeedReplies++ ;
  1547. X         return(RexxMsg) ;
  1548. X      } else
  1549. X         DeleteArgstring(RexxMsg->rm_Args[0]) ;
  1550. X   }
  1551. X   if (RexxMsg)
  1552. X      DeleteRexxMsg(RexxMsg) ;
  1553. X   closeRexxLib() ;
  1554. X   return(NULL) ;
  1555. X}
  1556. X/*
  1557. X *   This function is used to send out an ARexx message and return
  1558. X *   immediately.  Its single parameter is the command to send.
  1559. X */
  1560. Xstruct RexxMsg *asyncRexxCmd(s)
  1561. Xchar *s ;
  1562. X{
  1563. X   return(sendRexxCmd(s, NULL, NULL, NULL, NULL)) ;
  1564. X}
  1565. X/*
  1566. X *   This function sets things up to reply to the message that caused
  1567. X *   it when we get a reply to the message we are sending out here.
  1568. X *   But first the function we pass in, which actually handles the reply.
  1569. X *   Note how we get the message from the Args[2]; Args[0] is the command,
  1570. X *   Args[1] is this function, and Args[2]..Args[4] are any parameters
  1571. X *   passed to sendRexxCmd() as p1..p3.  We pass the result codes right
  1572. X *   along.
  1573. X */
  1574. Xstatic void replytoit(msg)
  1575. Xregister struct RexxMsg *msg ;
  1576. X{
  1577. X   register struct RexxMsg *omsg ;
  1578. X
  1579. X   omsg = (struct RexxMsg *)(msg->rm_Args[2]) ;
  1580. X   replyRexxCmd(omsg, msg->rm_Result1, msg->rm_Result2, NULL) ;
  1581. X   ReplyMsg(omsg) ;
  1582. X}
  1583. X/*
  1584. X *   This function makes use of everything we've put together so far,
  1585. X *   and functions as a synchronous Rexx call; as soon as the macro
  1586. X *   invoked here returns, we reply to `msg', passing the return codes
  1587. X *   back.
  1588. X */
  1589. Xstruct RexxMsg *syncRexxCmd(s, msg)
  1590. Xchar *s ;
  1591. Xstruct RexxMsg *msg ;
  1592. X{
  1593. X   return(sendRexxCmd(s, (APTR)&replytoit, msg, NULL, NULL)) ;
  1594. X}
  1595. X/*
  1596. X *   There are times when you want to pass back return codes or a
  1597. X *   return string; call this function when you want to do that,
  1598. X *   and return `1' from the user dispatch function so the main
  1599. X *   event loop doesn't reply (because we reply here.)  This function
  1600. X *   always returns 1.
  1601. X */
  1602. Xvoid replyRexxCmd(msg, primary, secondary, string)
  1603. X/*
  1604. X *   The first parameter is the message we are replying to.
  1605. X */
  1606. Xregister struct RexxMsg *msg ;
  1607. X/*
  1608. X *   The next two parameters are the primary and secondary return
  1609. X *   codes.
  1610. X */
  1611. Xregister long primary, secondary ;
  1612. X/*
  1613. X *   The final parameter is a return string.  This string is only
  1614. X *   returned if the primary return code is 0, and a string was
  1615. X *   requested.
  1616. X *
  1617. X *   We also note that we have replied to the message that came in.
  1618. X */
  1619. Xregister char *string ;
  1620. X{
  1621. X   STRPTR CreateArgstring() ;
  1622. X
  1623. X/*
  1624. X *   Note how we make sure the Rexx Library is open before calling
  1625. X *   CreateArgstring . . . and we close it down at the end, if possible.
  1626. X */
  1627. X   if (primary == 0 && (msg->rm_Action & (1L << RXFB_RESULT))) {
  1628. X      if (string && openRexxLib())
  1629. X         secondary = (long)CreateArgstring(string, (long)strlen(string)) ;
  1630. X      else
  1631. X         secondary = 0L ;
  1632. X   }
  1633. X   msg->rm_Result1 = primary ;
  1634. X   msg->rm_Result2 = secondary ;
  1635. X   closeRexxLib() ;
  1636. X}
  1637. SHAR_EOF
  1638. echo "extracting minrexx.h"
  1639. sed 's/^X//' << \SHAR_EOF > minrexx.h
  1640. X/*
  1641. X *   Includes for minrexx.c; please refer to that file for
  1642. X *   further documentation.
  1643. X */
  1644. X#include <rexx/rxslib.h>
  1645. X/*
  1646. X *   This is the list of functions we can access.  (Cheap forward
  1647. X *   declarations, too.)
  1648. X */
  1649. Xlong upRexxPort() ;
  1650. Xvoid dnRexxPort() ;
  1651. Xvoid dispRexxPort() ;
  1652. Xstruct RexxMsg *sendRexxCmd() ;
  1653. Xstruct RexxMsg *syncRexxCmd() ;
  1654. Xstruct RexxMsg *asyncRexxCmd() ;
  1655. Xvoid replyRexxCmd() ;
  1656. X/*
  1657. X *   Maximum messages that can be pending, and the return codes
  1658. X *   for two bad situations.
  1659. X */
  1660. X#define MAXRXOUTSTANDING (300)
  1661. X#define RXERRORIMGONE (100)
  1662. X#define RXERRORNOCMD (30)
  1663. X/*
  1664. X *   This is the association list you build up (statically or
  1665. X *   dynamically) that should be terminated with an entry with
  1666. X *   NULL for the name . . .
  1667. X */
  1668. Xstruct rexxCommandList {
  1669. X   char *name ;
  1670. X   APTR userdata ;
  1671. X} ;
  1672. SHAR_EOF
  1673. echo "extracting Makefile"
  1674. sed 's/^X//' << \SHAR_EOF > Makefile
  1675. Xall: freedraw origfreedraw
  1676. X
  1677. Xfreedraw: freedraw.o minrexx.o rexxglue.o
  1678. X    ln freedraw.o minrexx.o rexxglue.o -lc
  1679. X
  1680. Xfreedraw.o: freedraw.c minrexx.h
  1681. X    cc -DTALKTOREXX freedraw.c
  1682. X
  1683. Xminrexx.o: minrexx.c minrexx.h
  1684. X    cc minrexx.c
  1685. X
  1686. Xorigfreedraw: origfreedraw.o
  1687. X    ln origfreedraw.o -lc
  1688. X
  1689. Xorigfreedraw.o: freedraw.c
  1690. X    cc -o origfreedraw.o freedraw.c
  1691. X
  1692. Xclean:
  1693. X    delete freedraw.o origfreedraw.o freedraw origfreedraw minrexx.o
  1694. SHAR_EOF
  1695. echo "extracting freeedraw.uu"
  1696. sed 's/^X//' << \SHAR_EOF > freeedraw.uu
  1697. X
  1698. Xbegin 700 freedraw
  1699. XM```#\P`````````#``````````(```?Q````QP````$```/I```'\4[Z%L9&)
  1700. XM<F5E9')A=R`P+C`Q(&)Y(%)I8VAA<F0@32X@4F]S<P``04U)1T$@1G)E941RZ
  1701. XM87<@,"XP,0!C;VQO<@!B;W@`9F)O>`!L:6YE`'1O9G)O;G0`=&]B86-K`&5X3
  1702. XM:70`=F5R<VEO;@!S<&%W;@!.5?_^(&T`$")H`#(;:0`9__\0+0`52(!(P"\`Q
  1703. XM(&T`$"\H`#).NAZ>4$\P+0`*2,`O`#`M``A(P"\`(&T`$"\H`#).NAY<3^\`I
  1704. XM##`M``I(P"\`,"T`#$C`+P`@;0`0+R@`,DZZ'BI/[P`,,"T`#DC`+P`P+0`,5
  1705. XM2,`O`"!M`!`O*``R3KH>"D_O``PP+0`.2,`O`#`M``A(P"\`(&T`$"\H`#).)
  1706. XMNAWJ3^\`##`M``I(P"\`,"T`"$C`+P`@;0`0+R@`,DZZ'<I/[P`,$"W__TB`G
  1707. XM2,`O`"!M`!`O*``R3KH=YE!/3EU.=4Y5__PP+0`(4T!(P..`0>R`ACMP"`#_;
  1708. XM_$)M__Y@``&6,"W__L'\`")![(#(,BW__E)!P_P`(D/L@,C2B2&!"``P+?_^S
  1709. XMP?P`(D'L@-HR+?_^P_P`%$/L@5#2B2&!"``P+?_^P?P`(D'L@,PR+?_^2,&#T
  1710. XM_``$2$'#_``H5$$Q@0@`,"W__L'\`")![(#.,BW__DC!@_P`!,/\`!DQ@0@`M
  1711. XM,"W__L'\`")![(#0,;P`*`@`,"W__L'\`")![(#2,;P`&0@`,"W__L'\`")!3
  1712. XM[(#4,;P`D`@`,"W__L'\`")![(#60K`(`#`M__[!_``B0>R`WD*P"``P+?_^3
  1713. XMP?P`(D'L@.)",`@`,"W__L'\`")![(#D0K`(`#`M__[!_``B0>R`Z$)P"``PD
  1714. XM+?_^P?P`%$'L@5`QO``!"``P+?_^P?P`%$'L@5(QO``!"``P+?_^P?P`%$'LH
  1715. XM@50QO``F"``P+?_^P?P`%$'L@58QO``7"``P+?_^P?P`%$'L@5@QK0`("``PZ
  1716. XM+?_^P?P`%$'L@5I"L`@`,"W__L'\`!1![(%>0C`(`#`M__[!_``40>R!7Q&MD
  1717. XM__\(`%)M__XP+?_^L&W__&T`_F(P+?_\4T#!_``B0>R`R$*P"`!P`$Y=3G5.F
  1718. XM5?_^0FW__C`M__[!_``B0>R!H#(M__Y20</\`")#[(&@THDA@0@`,"W__L'\!
  1719. XM`")![(&D0G`(`#`M__[!_``B0>R!IC(M__[#_``*,8$(`#`M__[!_``B0>R!!
  1720. XMJ#&\`'`(`#`M__[!_``B0>R!JC&\``H(`#`M__[!_``B0>R!K#&\`)((`#`M4
  1721. XM__[!_``B0>R!KD*P"``P+?_^P?P`(D'L@;(R+?_^P_P`%$/L@BC2B2&!"``P(
  1722. XM+?_^P?P`(D'L@;9"L`@`,"W__L'\`")![(&Z0C`(`#`M__[!_``B0>R!O$*P7
  1723. XM"``P+?_^P?P`(D'L@<!"<`@`,"W__L'\`!1![((H0C`(`#`M__[!_``40>R"_
  1724. XM*1&\``$(`#`M__[!_``40>R"*A&\``$(`#`M__[!_``40>R"+$)P"``P+?_^S
  1725. XMP?P`%$'L@BXQO``!"``P+?_^P?P`%$'L@C!"L`@`,"W__L'\`!1![((X0K`(T
  1726. XM`%)M__X,;0`$__YM`/Z20JR"!D'Z`"0I2((T0?H`)BE(@DA!^@`I*4B"7$'ZY
  1727. XM`"PI2()P<`!.74YU17)A<V4@06QL`$AO;&QO=R!";W@`1FEL;&5D($)O>`!0]
  1728. XM96X@1')A=P``3E4``$'L@I8I2()X.7P`"H)\0FR"?CE\`#*"@#E\``J"@CE\@
  1729. XM``&"A$'Z`$0I2(*&0>R`R"E(@HI"K(*6.7P`08*:0FR"G#E\`%6"GCE\``J"`
  1730. XMH#E\``&"HD'Z`!HI2(*D0>R!H"E(@JAP`$Y=3G5#;VQO<@!$<F%W36]D90``_
  1731. XM3E7^RAM\``'_^SM\`![_^#M\`![_]CM\`!3_]#M\`!3_\D)M_]I";?_80FW_)
  1732. XMUD)M_]1";?_20FW_T$)M_\Y(>``!2'H&JDZZ&-Q03RE`@,!*K(#`9@A"ITZZ>
  1733. XM%7!83TAX``%(>@:<3KH8O%!/*4"`Q$JL@,1F"$*G3KH54%A/2&R`!DZZ&998G
  1734. XM3RE`@K1F"$*G3KH5.%A/(&R"M!`H`#9(@#E`@K@@;(*T$"@`-TB`.4""NB!LF
  1735. XM@K0B;(*T$"D`.$B`,B@`"))`4T$Y08*\(&R"M")L@K00*0`Y2(`R*``*DD!3\
  1736. XM03E!@KX_/``"3KKZ\E1/3KK\Q$ZZ_HQ(;()X+RR"M$ZZ&2103T*G(&R"M"\H.
  1737. XM`#).NABZ4$\0+?_[2(`_`"!L@K0O*``R3KH8E%Q/2'H&H$AZ!>A(;(`V2'H%;
  1738. XMUTZZ"<I/[P`0*T#_RD(M_LH[?``!_^I@+#`M_^I(P.6`(&T`"B\P"`!(;?[*&
  1739. XM3KH38%!/2'H%K4AM_LI.NA-24$]2;?_J,"W_ZK!M``AMRDHM_LIG"DAM_LI.<
  1740. XMN@S@6$]*;("09P`%*"!L@K0B:`!6<``0*0`/<@'AH8*M_\HO`4ZZ%ZY83TZZ:
  1741. XM"D!";?_:(&R"M"\H`%9.NA<P6$\K0/_\9P`$*B!M__PK:``4_^X@;?_\.V@`Y
  1742. XM&/_L(&R"M#MH``[_ZB!L@K0[:``,_^@O+?_\3KH73EA/,"W_ZK!L@KAM'C`MF
  1743. XM_^JP;(*\;A0P+?_HL&R"NFT*,"W_Z+!L@KYO"#M\``'_V&`$0FW_V&<,2FW_1
  1744. XMTF<&.WP``?_6("W_[F```WH[?``!_]I@``.@(&R"M!`H`#9(@#E`@K@@;(*TD
  1745. XM$"@`-TB`.4""NB!L@K0B;(*T$"D`.$B`,B@`"))`4T$Y08*\(&R"M")L@K00!
  1746. XM*0`Y2(`R*``*DD!303E!@KY@``-,0FR`D&```T1P`#`M_^Q@``'`0FW_UD)M.
  1747. XM_])@``'.2FW_V&8``<9*;?_49SX[?``!_])";?_60J<@;(*T+R@`,DZZ%M)0K
  1748. XM3S`M_^A(P"\`,"W_ZDC`+P`@;(*T+R@`,DZZ%H!/[P`,8``!@DIM_]!G``#(2
  1749. XM0J<@;(*T+R@`,DZZ%I903T)M_]`@;(*T"*@````92FW_SF=Z,"W_]+!M__AL%
  1750. XM#CMM__3_YCMM__C_XF`,.VW_^/_F.VW_]/_B,"W_\K!M__9L#CMM__+_Y#MMX
  1751. XM__;_X&`,.VW_]O_D.VW_\O_@,"W_X$C`+P`P+?_B2,`O`#`M_^1(P"\`,"W_S
  1752. XMYDC`+P`@;(*T+R@`,DZZ%>I/[P`48"00+?_[2(`_`"\L@K0_+?_V/RW_^#\M$
  1753. XM__(_+?_T3KKW$D_O``Y@``"T.VW_ZO_X.VW_ZO_T.VW_Z/_V.VW_Z/_R2'@`1
  1754. XM`B!L@K0O*``R3KH5ME!/.WP``?_0(&R"M`CH````&1`M__M(@#\`+RR"M#\M,
  1755. XM__8_+?_X/RW_\C\M__1.NO:P3^\`#F!20FW_T"!L@K0(J````!D0+?_[2(`_'
  1756. XM`"\L@K0_+?_V/RW_^#\M__(_+?_T3KKV?$_O``Y@'F``_4*0O````&AG`/Y&3
  1757. XM4X!GNI"\````?V<`_BQ@XF```5X,;?___^QG``#>,"W_[,!\`!\[0/_>,"W_/
  1758. XM[.I(P'P`/SM`_]QP`#`M_]Y@``"L&VW_W?_[$"W_^TB`2,`O`"!L@K0O*``R$
  1759. XM3KH4SE!/8```F'``,"W_W&!J0J<@;(*T+R@`,DZZ%,)03S`L@KY(P"\`,"R"5
  1760. XMO$C`+P`P+(*Z2,`O`#`L@KA(P"\`(&R"M"\H`#).NA1R3^\`%&`Z0FW_U$)M%
  1761. XM_\Y@,$)M_]0[?``!_\Y@)#M\``'_U&`<8!K_AO_(_]+_WK"\````!&3NXX`PX
  1762. XM.P#L3OL``&`08`Y*@&<`_U)3@&<`_VY@\&!T2FW_T&<D$"W_^TB`/P`O+(*T[
  1763. XM/RW_]C\M__@_+?_R/RW_]$ZZ]49/[P`.0FW_T$)M_]9";?_2(&R"M`BH````#
  1764. XM&6`R8#!5@&<`_(Y=@&<`_.11@&<`_'B0O````/!G`/ZZD+P```$`9P#\PI"\J
  1765. XM``?^`&>.8,Y@`/O$2FW_VF<``+A*;?_89@``L$IM_])G3DIM_]9G)D)M_]8PD
  1766. XM+?_H2,`O`#`M_^I(P"\`(&R"M"\H`#).NA-83^\`#&`@,"W_Z$C`+P`P+?_J1
  1767. XM2,`O`"!L@K0O*``R3KH3)$_O``Q@6DIM_]!G5!`M__M(@#\`+RR"M#\M__8_U
  1768. XM+?_X/RW_\C\M__1.NO1J3^\`#CMM_^K_^#MM_^C_]A`M__M(@#\`+RR"M#\M9
  1769. XM__8_+?_X/RW_\C\M__1.NO0Z3^\`#F``^M1.N@32+RR"M$ZZ$S!83R\L@K1.$
  1770. XMNA,R6$](>``!3KH.Y%A/3EU.=6EN='5I=&EO;BYL:6)R87)Y`&=R87!H:6-S-
  1771. XM+FQI8G)A<GD`9G)E961R87<`9F0`(```3E7__DCG""`@;0`()%!X`$)M__X,-
  1772. XM$@`@;@A*$F<$4HI@\G`PL!)N)`P2`#EN'CM\``'__B!*4HH0$$B`,@3#_``*6
  1773. XMT$$X`)A\`#!@UDIM__YF!$)L@L@@;0`(((HP!$S?!!!.74YU3E4``"\$(&T`<
  1774. XM"`P0`"!O#B!M``A*$&<&4JT`"&#H>`!@&DAM``A.NO]R6$\R!$C!XX%![(+`-
  1775. XM,8`8`%)$N&T`#&W@*!].74YU3E4``$CG"#`D;0`()FT`##E\``&"R$JL@K1GG
  1776. XM<$)L@LH@;(*T(F@`,A`I`!E(@#@`,"R`DDC`+P`@;(*T+R@`,DZZ$:Q03R\MJ
  1777. XM`!`O"B!K``1.D%!/,`1(P"\`(&R"M"\H`#).NA&*4$]*;(+(9A9"IT*G,"R"Y
  1778. XMR$C`+P`O"DZZ!IA/[P`03-\,$$Y=3G5"ITAX``I(>``4+PI.N@9\3^\`$&#B[
  1779. XM3E4``#\\``$O+0`,3KK_"%Q/.6R"P("23EU.=4Y5```P+0`(2,#C@$'L@L`R\
  1780. XM,`@`LFR"N&P2,"T`"$C`XX!![(+`,:R"N`@`,"T`"$C`XX!![(+`,C`(`+)LS
  1781. XM@KQO$C`M``A(P..`0>R"P#&L@KP(`%)M``@P+0`(2,#C@$'L@L`R,`@`LFR"Q
  1782. XMNFP2,"T`"$C`XX!![(+`,:R"N@@`,"T`"$C`XX!![(+`,C`(`+)L@KYO$C`M]
  1783. XM``A(P..`0>R"P#&L@KX(`$Y=3G5.50``/SP`!"\M``Q.NOY`7$]"9TZZ_SY4R
  1784. XM3S\\``).NO\T5$\_+("2+RR"M#\L@L8_+(+$/RR"PC\L@L!.NO&"3^\`#DY=J
  1785. XM3G5.50``+P0_/``$+RT`#$ZZ_?9<3T)G3KK^]%1//SP``DZZ_NI43S`L@L"P*
  1786. XM;(+$;PXX+(+`.6R"Q(+`.42"Q#`L@L*P;(+&;PXX+(+".6R"QH+".42"QC`L`
  1787. XM@L9(P"\`,"R"Q$C`+P`P+(+"2,`O`#`L@L!(P"\`(&R"M"\H`#).N@^J3^\`.
  1788. XM%"@?3EU.=4Y5```_/``$+RT`#$ZZ_6Q<3T)G3KK^:E1//SP``DZZ_F!43S`L-
  1789. XM@L)(P"\`,"R"P$C`+P`@;(*T+R@`,DZZ#TY/[P`,,"R"QDC`+P`P+(+$2,`O^
  1790. XM`"!L@K0O*``R3KH/'$_O``Q.74YU3E4``"\L@K1.N@_"6$].74YU3E4``"\L6
  1791. XM@K1.N@^D6$].74YU3E4``$)L@)!.74YU3E4``#E\``&"RB\L@`)"IT*G+RT`%
  1792. XM"$ZZ!"A/[P`03EU.=4Y5```@;0`,#!``(&X.(&T`#$H09P92K0`,8.@O+0`,'
  1793. XM3KH#CEA/3EU.=5)A9&EC86P@17EE($UI;E)E>'@@,"XT`$Y5``!*K0`,9P9*;
  1794. XMK0`49@9P`$Y=3G5*K("B9CY.N@VP+RT`"$ZZ#8Q83TJ`9A!"IR\M``A.N@R`9
  1795. XM4$\I0("B3KH-\$JL@*)G$B!L@*)P`!`H``]R`>&A*4&`L"EM``R`J"EM`!"`D
  1796. XMM"EM`!2`N"`L@+!@H$Y5``!*K("L9A1*K(+,9PXO+(+,3KH,'EA/0JR"S$Y=S
  1797. XM3G5.50``2JR`HF=4+RR`HDZZ#:)83SE\``&`IDJL@+QG&B!L@+PA?````&0`L
  1798. XM("\L@+Q.N@V,6$]"K("\2JR`K&<.+RR`HDZZ#9183V$:8.QACB\L@*).N@Q8L
  1799. XM6$]"K("B0JR`L$Y=3G5.50``2.<,,$JL@*)F"$S?##!.74YU+RR`HDZZ#.18Y
  1800. XM3R1`2H!G``#8#"H`!P`(9BY*J@`L9PHO"B!J`"Q.D%A/+RH`*$ZZ`R)83R\*H
  1801. XM3KH#(%A/4ZR`K$ZZ_R!@``">*"H`*"!$2A!O#"!$#!``(&X$4H1@[D*J`"!"9
  1802. XMJ@`D>@!*;("F9PHE?````&0`(&!<*4J`O"9L@*A@+"\$+Q-A9%!/2D!F'B\34
  1803. XM3KH$E%A/2,#0A"\`+PLO"B!L@+A.D$_O``Q@!E"+2I-FT$J39AY*K("T9Q`OV
  1804. XM"B\J`"A.N@'H4$]Z`6`()7P````>`"!"K("\2D5F""\*3KH,8EA/8`#_&F``S
  1805. XM_PY.50``2.<`,"1M``@F;0`,2A)G*!`2L!-G'!`32(#0?``@$A)(@;!!9A)PW
  1806. XM8;`2;@P,$@!Z;@92BE*+8-00$DB`3-\,`$Y=3G5.50``2JR"S&<&<`%.74YU8
  1807. XM0J=(>@`63KH+P%!/*4""S&<$<`%@`G``8.)R97AX<WES;&EB+FQI8G)A<GD`:
  1808. XM`$Y5``!(YP`P2JR`HF<*#*P```$K@*QO"G``3-\,`$Y=3G67RV&<2D!G``"B;
  1809. XM(&R`HB\H``HO+("T+RR`HDZZ`9Q/[P`,)D!*@&<``((O+0`(3KH#8EA/2,`O2
  1810. XM`"\M``A.N@)(4$\G0``H9V(G?`$`````'"=M``P`+"=M`!``,"=M`!0`-"=M]
  1811. XM`!@`.$'Z`%8G2``*3KH*N$AZ`$].N@J46$\D0$J`9PHO"R\*3KH+"E!/3KH*B
  1812. XM_"`*9PI2K("L(`M@`/]:+RL`*$ZZ`1A83R`+9P@O"TZZ`1)83TZZ_19P`&``P
  1813. XM_SI215A8`%)%6%@`3E4``$*G0J="IT*G+RT`"$ZZ_P)/[P`43EU.=4Y5``!(F
  1814. XMYP`P)&T`""9J`#!"IR\J`"0O*@`@+PMA-$_O`!`O"TZZ"J)83TS?#`!.74YUF
  1815. XM3E4``$*G0J<O+0`,2'K_P"\M``A.NOZP3^\`%$Y=3G5.50``2.<,,"1M``@H'
  1816. XM+0`,*BT`$"9M`!1*A&8N""H``0`=9R8@"V<@3KK^/DI`9Q@O"TZZ`B983TC`>
  1817. XM+P`O"TZZ`0Y03RH`8`)Z`"5$`"`E10`D3KK\0DS?##!.74YU,CS_4F!P,CS^2
  1818. XMJF!J,CS_$&!D<I1@8#(\_S1@6C(\_FA@5#(\_W!@3C(\_WQ@2#(\_VI@0C(\A
  1819. XM_GI@/#(\_G1@-C(\_FY@,#(\_F)@*C(\_H!@)#(\_TQ@'G*(8!HR//\68!1R0
  1820. XMFF`0,CS_(F`*,CS_'&`$,CS_6$SO`P``!"`O``PO#BQY```"RDZV$``L7TYUB
  1821. XM,CS_=F#@,CS_.F#:,CS^C,CS^GF#.,CS^I&#(,CS_1F#",CS_0&"\,CS^J
  1822. XM1&"V,CS_!&"P,CS^_F"J,CS^^&"D,CS^\F">,CS^[&"8,CS^X&"2,CS^AF",_
  1823. XM,CS^F&"&<H)@(#(\_RA@&C(\_V1@%#(\_E!@#G*.8`HR//\N8`0R//[F(&\`F
  1824. XM!"`O``A@`/]B,CS^R&`0,CS^/F`*,CS^VF`$,CS^."`O``1@`/]$,GS^SF`0"
  1825. XM,GS^PF`*,GS_7F`$,GS^DB!O``1,[P`#``@O#BQY```"RDZVD``L7TYU3.\#L
  1826. XM`P`$P8C#B2\.+'D```+*3J[^2BQ?3G5,[P,#``3!B,.)+PXL>0```LI.KOZ\:
  1827. XM+%].=4SO`P,`!,&(PXDO#BQY```"RDZN_K8L7TYU3.\#`P`$P8C#B2\.+'D`0
  1828. XM``+*3J[^L"Q?3G4@;P`$,CS^U&$`_J`B;P`((H%.=2`O``1RH&$`_HXB;P`(`
  1829. XM(HA.=2!O``0@"$H89OR1P"`(4X!.=6%P0^R`HD7L@**UR68.,CP`GFL(=``BW
  1830. XMPE')__PI3X+0+'@`!"E.@M1(YX"`""X`!`$I9Q!+^@`(3J[_XF`&0J?S7TYSL
  1831. XM0_H`($ZN_F@I0(+89@PN/``#@`=.KO^48`1.N@`:4$].=61O<RYL:6)R87)Y(
  1832. XM`$GY``!__DYU3E4``"\*2'D``0``,"R`F,'\``8O`$ZZ!LHI0(+<4$]F%$*GG
  1833. XM2'D``0``3KH%H%!/+FR"T$YU(&R"W$)H``0@;(+<,7P``0`0(&R"W#%\``$`5
  1834. XM"B!L@M`@+(+0D*@`!%"`*4""X"!L@N`@O$U!3EA"ITZZ!HXD0$JJ`*Q83V<N@
  1835. XM+RT`#"\M``@O"DZZ`*XY?``!@N0@;(+<`&B````$(&R"W`!H@```"D_O``Q@S
  1836. XM0DAJ`%Q.N@;^2&H`7$ZZ!H(I0(+F(&R"YDJH`"103V<0(&R"YB)H`"0O$4ZZ5
  1837. XM!+I83R\L@N8O"DZZ`F@I;(+F@NI03TZZ!*X@;(+<((!.N@2Z(&R"W"%```9G=
  1838. XM%DAX`^U(>@`J3KH$EB!L@MPA0``,4$\O+(+J/RR"[DZZ[1!"9TZZ`M103R1?:
  1839. XM3EU.=2H`3E4``$CG##`D;0`0(&T`"$JH`*QG&"!M``@@*`"LY8`H`"!$("@`[
  1840. XM$.6`)D!@!"9L@)H0$TB`2,#0K0`,5(`Y0(+P0J<P+(+P2,`O`$ZZ!5PI0(+R:
  1841. XM4$]F"$S?##!.74YU$!-(@#H`/P4@2U*(+P@O+(+R3KH!?C`%2,`@0-'L@O)#N
  1842. XM^@%$$-EF_#\M``XO"B\L@O).N@$Z(&R"\D(P4``Y?``!@NXP!4C`T*R"\B9`*
  1843. XM4HLD2T_O`!00$TB`.@"P?``@9QBZ?``)9Q*Z?``,9PRZ?``-9P:Z?``*9@12G
  1844. XMBV#8#!,`(&UZ#!,`(F8N4HL@2U*+$!!(@#H`9QX@2E**$(6Z?``B9A`,$P`BT
  1845. XM9@12BV`&0BK__V`"8-9@."!+4HL0$$B`.@!G)KI\`"!G(+I\``EG&KI\``QG$
  1846. XM%+I\``UG#KI\``IG""!*4HH0A6#.($I2BD(02D5F`E.+4FR"[F``_UI"$D*G5
  1847. XM,"R"[E)`2,#E@"\`3KH$.BE`@NI03V8(0FR"[F``_MAZ`"9L@O)@)#`%2,#E<
  1848. XM@"!L@NHABP@`($L@"$H89OR1P%.(,`A20$C`U\!21;IL@NYMUC`%2,#E@"!LV
  1849. XM@NI"L`@`8`#^E"``,#Q__V`$,"\`#"!O``1*&&;\4T@B;P`(4T`0V5?(__QGY
  1850. XM`D(0("\`!$YU3.\#```$(`@R+P`,8`(0V5?)__QG!E)!8`)"&%')__Q.=4Y5>
  1851. XM``!(YPXP)&T`"$*G2'H`CDZZ`_XI0(+V4$]F"$S?#'!.74YU(&T`#")H`"0O!
  1852. XM*0`$3KH$K"@`6$]G4DAZ`&T@1"\H`#9.N@1^)D!*@%!/9S1(>`/M+PM.N@(`U
  1853. XM+`!03V<D(`;E@"H`($4E:``(`*0E1@"<2'@#[4AZ`#A.N@'<)4``H%!/+P1.D
  1854. XMN@1*6$\O+(+V3KH"!$*L@O983V"`:6-O;BYL:6)R87)Y`%=)3D1/5P`J`$Y5N
  1855. XM``!*K(+Z9P8@;(+Z3I`_+0`(3KH`"%1/3EU.=4Y5__PO!#`M``A(P"M`__Q*(
  1856. XMK(+<9RAX`&`*/P1.N@#^5$]21+AL@)AM\#`L@)C!_``&+P`O+(+<3KH"Q%!/B
  1857. XM2JR"_F<&(&R"_DZ02JR`GF<*+RR`GDZZ`4A83TJL@P)G""!L@P(@K(,&2JR#,
  1858. XM"F<*+RR#"DZZ`5983TJL@PYG"B\L@PY.N@%&6$]*K(,29PHO+(,23KH!-EA/5
  1859. XM2JR#%F<*+RR#%DZZ`2983RQX``0(+@`$`2EG%"\-2_H`"DZN_^(J7V`&0J?S$
  1860. XM7TYS2JR"YF8P2JR"\F<H,"R"\$C`+P`O+(+R3KH"'#`L@NY20$C`Y8`O`"\L<
  1861. XM@NI.N@((3^\`$&`.3KH!\B\L@N9.N@)N6$\@+?_\+FR"T$YU*!].74YU3E4`F
  1862. XM`$CG#B`X+0`(,`3!_``&)$#5[(+<2D1M"KAL@)AL!$J29A`Y?``"@QIP_TS?U
  1863. XM!'!.74YU""H`!P`$9@@O$DZZ``I83T*2<`!@XB(O``0L;(+83N[_W"(O``0LL
  1864. XM;(+83N[_@BQL@MA.[O_*3.\`!@`$+&R"V$[N_^(L;(+83N[_Q$[Z``(B+P`$>
  1865. XM+&R"V$[N_Z9(YP$$3.\@@``,+&R"U$ZN_Y1,WR"`3G5.^@`"(F\`!"QL@M1.4
  1866. XM[OYB3E4``$CG""!(>/__3KH`T"@`L+S_____6$]F"G``3-\$$$Y=3G5(>0`!D
  1867. XM``%(>``B3KH`N"1`2H!03V8,+P1.N@#X<`!83V#6)6T`"``*%6T`#P`)%7P`Q
  1868. XM!``(0BH`#A5$``]"ITZZ`*(E0``02JT`"%A/9PHO"DZZ`%I83V`*2&H`%$ZZ'
  1869. XM`-!83R`*8)).50``+PHD;0`(2JH`"F<(+PI.N@#P6$\5?`#_``@E?/____\`"
  1870. XM%'``$"H`#R\`3KH`?$AX`"(O"DZZ`%Y/[P`,)%].74YU(F\`!"QL@M1.[OZ>7
  1871. XM("\`!"QL@M1.[OZV3OH``DSO``,`!"QL@M1.[O\Z(F\`!"QL@M1.[OYZ3OH`?
  1872. XM`B)O``0L;(+43N[^VD[Z``(L;(+43N[_?$[Z``(B;P`$("\`""QL@M1.[O\N5
  1873. XM("\`!"QL@M1.[OZP3OH``B!O``0L;(+43N[^C"!O``0@B%B00J@`!"%(``A.,
  1874. XM=4[Z``(L;(+4(F\`!"`O``A.[OW8+&R"U$[N_W9,[P,```0L;(+43N[^DB)O6
  1875. XM``0L;(+43N[^F$[Z``(B;P`$+&R"U$[N_H8@+P`$+&R"U$[N_L).^@`"(&\`G
  1876. XM!"QL@M1.[OZ`(F\`!$SO``,`""QL@,1.[O\*(F\`!$SO``,`""QL@,1.[O\0J
  1877. XM(F\`!$SO``\`""QL@,1.[O[.(F\`!"`O``@L;(#$3N[^JB)O``0@+P`(+&R`[
  1878. XMQ$[N_IY,[P,```0L;(+V3N[_H"!O``0L;(+V3N[_IB!O``0L;(+V3N[_LB!OL
  1879. XM``0L;(#`3N[_RB!O``0L;(#`3N[_N"!O``0L;(#`3N[_-$SO`P``!"QL@,!.!
  1880. XM[O[X(&\`!"QL@,!.[O[.(&\`!"QL@,!.[O[(```#[`````<````!```6A```5
  1881. XM%FH``!90```6-@``%AP``!4^```7/`````````/R```#Z@```"@````$``H`B
  1882. XM"@)8`+0``0`(`QH``!(/```````````````F````````````9``C_____P`!)
  1883. XM````.@``#>@```!````.L````$0```[X````20``#X0```!.```/[````%8`R
  1884. XM``_^````70``$!````!B```0'````&H``!`^`````````````@`$``@`$``@.
  1885. XM``$``0``$&@`%``````````````#[````!4``````````````!X````T````D
  1886. XM.````#P```!`````1````$@```!,````4````%0```!8````7````&````!DH
  1887. XL````:````&P```!P````=````'@```"2`````````_(```/K`````0```_)D_
  1888. X``
  1889. Xend
  1890. Xsize 8504
  1891. SHAR_EOF
  1892. echo "extracting aspline.fd"
  1893. sed 's/^X//' << \SHAR_EOF > aspline.fd
  1894. X/* given four control points (that's eight arguments) this draws a bspline */
  1895. X
  1896. Xparse arg x1 y1 x2 y2 x3 y3 x4 y4
  1897. X
  1898. Xlength = max(abs(x1-x4), abs(y1-74))
  1899. X
  1900. Xif (length = 0) then exit
  1901. X
  1902. Xd1 = abs((x1 - x4) * (y2 - y4) - (y1 - y4) * (x2 - x4)) / length
  1903. Xd2 = abs((x1 - x4) * (y3 - y4) - (y1 - y4) * (x3 - x4)) / length
  1904. X
  1905. X/* if they are colinear, simply draw a line. */
  1906. X
  1907. Xif (d1 < 0.5) & (d2 < 0.5) then do
  1908. X
  1909. X   address 'freedraw' 'Line ' trunc(x1) trunc(y1) trunc(x4) trunc(y4)
  1910. X
  1911. X/* otherwise invoke recursively on substrings */
  1912. X
  1913. Xend
  1914. Xelse do
  1915. X
  1916. X   x12 = (x1 + x2) / 2
  1917. X   y12 = (y1 + y2) / 2
  1918. X   x23 = (x2 + x3) / 2
  1919. X   y23 = (y2 + y3) / 2
  1920. X   x34 = (x3 + x4) / 2
  1921. X   y34 = (y3 + y4) / 2
  1922. X   x123 = (x12 + x23) / 2
  1923. X   y123 = (y12 + y23) / 2
  1924. X   x234 = (x23 + x34) / 2
  1925. X   y234 = (y23 + y34) / 2
  1926. X   x1234 = (x123 + x234) / 2
  1927. X   y1234 = (y123 + y234) / 2
  1928. X
  1929. X   address 'freedraw' 'Spawn aspline ' x1 y1 x12 y12 x123 y123 x1234 y1234
  1930. X   address 'freedraw' 'Spawn aspline ' x1234 y1234 x234 y234 x34 y34 x4 y4
  1931. X
  1932. Xend
  1933. SHAR_EOF
  1934. echo "extracting bspline.fd"
  1935. sed 's/^X//' << \SHAR_EOF > bspline.fd
  1936. X/* given four control points (that's eight arguments) this draws a bspline */
  1937. X
  1938. Xparse arg x1 y1 x2 y2 x3 y3 x4 y4
  1939. X
  1940. Xlength = max(abs(x1-x4), abs(y1-74))
  1941. X
  1942. Xif (length = 0) then exit
  1943. X
  1944. Xd1 = abs((x1 - x4) * (y2 - y4) - (y1 - y4) * (x2 - x4)) / length
  1945. Xd2 = abs((x1 - x4) * (y3 - y4) - (y1 - y4) * (x3 - x4)) / length
  1946. X
  1947. X/* if they are colinear, simply draw a line. */
  1948. X
  1949. Xif (d1 < 0.5) & (d2 < 0.5) then do
  1950. X
  1951. X   address 'freedraw' 'Line ' trunc(x1) trunc(y1) trunc(x4) trunc(y4)
  1952. X
  1953. X/* otherwise invoke recursively on substrings */
  1954. X
  1955. Xend
  1956. Xelse do
  1957. X
  1958. X   x12 = (x1 + x2) / 2
  1959. X   y12 = (y1 + y2) / 2
  1960. X   x23 = (x2 + x3) / 2
  1961. X   y23 = (y2 + y3) / 2
  1962. X   x34 = (x3 + x4) / 2
  1963. X   y34 = (y3 + y4) / 2
  1964. X   x123 = (x12 + x23) / 2
  1965. X   y123 = (y12 + y23) / 2
  1966. X   x234 = (x23 + x34) / 2
  1967. X   y234 = (y23 + y34) / 2
  1968. X   x1234 = (x123 + x234) / 2
  1969. X   y1234 = (y123 + y234) / 2
  1970. X
  1971. X   address 'freedraw' 'bspline ' x1 y1 x12 y12 x123 y123 x1234 y1234
  1972. X   address 'freedraw' 'bspline ' x1234 y1234 x234 y234 x34 y34 x4 y4
  1973. X
  1974. Xend
  1975. SHAR_EOF
  1976. echo "extracting sample.fd"
  1977. sed 's/^X//' << \SHAR_EOF > sample.fd
  1978. X/* draw something with freedraw */
  1979. X
  1980. Xaddress 'freedraw'
  1981. X
  1982. Xcolor = 0
  1983. X
  1984. Xdo i = 20 to 400
  1985. X   'Color ' color
  1986. X   color = color + 1
  1987. X   if color > 3 then color = 0
  1988. X   'Line ' 20 i i 400
  1989. Xend i
  1990. SHAR_EOF
  1991. echo "extracting saspline.fd"
  1992. sed 's/^X//' << \SHAR_EOF > saspline.fd
  1993. X/* invokes aspline with some sample values */
  1994. X'aspline 314 159 10 9 456 44 536 141'
  1995. Xexit
  1996. SHAR_EOF
  1997. echo "extracting sbspline.fd"
  1998. sed 's/^X//' << \SHAR_EOF > sbspline.fd
  1999. X/* invokes aspline with some sample values */
  2000. X'bspline 314 159 10 9 456 44 536 141'
  2001. Xexit
  2002. SHAR_EOF
  2003. echo "extracting version.fd"
  2004. sed 's/^X//' << \SHAR_EOF > version.fd
  2005. X/* gets the version from freedraw */
  2006. X
  2007. Xoptions results
  2008. X
  2009. Xaddress 'freedraw' 'Version'
  2010. X
  2011. Xsay result
  2012. SHAR_EOF
  2013. echo "End of archive 1 (of 1)"
  2014. # if you want to concatenate archives, remove anything after this line
  2015. exit
  2016.